GitPedia

Saaskit

A modern SaaS template built on Fresh.

From denoland·Updated June 28, 2026·View on GitHub·

[Deno SaaSKit](https://deno.com/saaskit) is an open-sourced, highly performant template for building your SaaS quickly and easily. The project is written primarily in TypeScript, distributed under the MIT License license, first published in 2023. It has gained significant community traction with 1,325 stars and 168 forks on GitHub. Key topics include: deno, fresh, saas, saas-boilerplate, typescript.

Latest release: v0.7.0
December 19, 2023View Changelog →

⚠️ SaaSKit is no longer actively maintained. ⚠️

Deno SaaSKit

Discord Chat
CI
codecov
Built with the Deno Standard Library

Deno SaaSKit is an open-sourced, highly performant
template for building your SaaS quickly and easily.

Note: this project is in beta. Design, workflows, and user accounts are
subject to change.

Features

  • Deno's built-in formatter,
    linter and
    test runner and TypeScript support
  • Next-gen web framework with Fresh
  • In-built data persistence with Deno KV
  • High-level OAuth with Deno KV OAuth
  • Modern CSS framework with Tailwind CSS
  • Responsive, SaaS-oriented design
  • Dashboard with users view and statistics chart
  • Stripe integration (optional)
  • First-class web performance
  • REST API
  • Blog with RSS feed and social sharing icons
  • HTTP security headers

Get Started

Get Started Locally

Before starting, you'll need:

  • A GitHub account
  • The Deno CLI and
    Git installed on your machine

To get started:

  1. Clone this repo:
    bash
    git clone https://github.com/denoland/saaskit.git cd saaskit
  2. Create a new .env file.
  3. Navigate to GitHub's
    New OAuth Application page.
  4. Set Application name to your desired application name. E.g. ACME, Inc.
  5. Set Homepage URL to http://localhost:8000.
  6. Set Authorization callback URL to http://localhost:8000/callback.
  7. Click Register application.
  8. Copy the Client ID value to the .env file:
    bash
    GITHUB_CLIENT_ID=<GitHub OAuth application client ID>
  9. On the same web page, click Generate a new client secret.
  10. Copy the Client secret value to the .env file on a new line:
    bash
    GITHUB_CLIENT_SECRET=<GitHub OAuth application client secret>
  11. Start the server:
    bash
    deno task start
  12. Navigate to http://localhost:8000 to start playing with your new SaaS app.

Set Up Stripe (Optional)

This guide will enable test Stripe payments, the pricing page, and "Premium
user" functionality.

Before starting, you'll need:

To get started:

  1. Navigate to the
    API keys page on the
    Developers dashboard.
  2. In the Standard keys section, click Reveal test key on the Secret
    key
    table row.
  3. Click to copy the value and paste to the .env file:
    bash
    STRIPE_SECRET_KEY=<Stripe secret key>
  4. Run the Stripe initialization script:
    bash
    deno task init:stripe
  5. Copy the Stripe "Premium Plan" price ID to the .env file:
    bash
    STRIPE_PREMIUM_PLAN_PRICE_ID=<Stripe "Premium Plan" price ID>
  6. Begin
    listening locally to Stripe events:
    bash
    stripe listen --forward-to localhost:8000/api/stripe-webhooks --events=customer.subscription.created,customer.subscription.deleted
  7. Copy the webhook signing secret to the .env file:
    bash
    STRIPE_WEBHOOK_SECRET=<Stripe webhook signing secret>
  8. Start the server:
    bash
    deno task start
  9. Navigate to http://localhost:8000 to start playing with your new SaaS app
    with Stripe enabled.

Note: You can use
Stripe's test credit cards to make test
payments while in Stripe's test mode.

Bootstrap the Database (Optional)

Use the following commands to work with your local Deno KV database:

  • deno task db:seed - Populate the database with data from the
    Hacker News API.
  • deno task db:dump > backup.json - Write all database entries to
    backup.json.
  • deno task db:restore backup.json - Restore the database from backup.json.
  • deno task db:reset - Reset the database. This is not recoverable.

Customize and Extend

Global Constants

The utils/constants.ts file includes global values used
across various aspects of the codebase. Update these values according to your
needs.

Create a Blog Post

  1. Create a .md file in the /posts with the filename as the slug of
    the blog post URL. E.g. a file with path /posts/hello-there.md will have
    path /blog/hello-there.

  2. Write the
    Front Matter
    then Markdown text to define
    the properties and content of the blog post.

    md
    --- title: This is my first blog post! publishedAt: 2022-11-04T15:00:00.000Z summary: This is an excerpt of my first blog post. --- # Heading 1 Hello, world! ```javascript console.log("Hello World"); ```
  3. Start the server:

    bash
    deno task start
  4. Navigate to the URL of the newly created blog post. E.g.
    http://localhost:8000/blog/hello-there.

See other examples of blog post files in /posts.

Themes

You can customize theme options such as spacing, color, etc. By default, Deno
SaaSKit comes with primary and secondary colors predefined within
tailwind.config.ts. Change these values to match your desired color scheme.

Cover Image

To replace the cover image, replace the /static/cover.png
file. If you'd like to change the filename, also be sure to change the
imageUrl property in the <Head /> component.

Deploy to Production

This section assumes that a
local development environment is already set up.

  1. Navigate to your
    GitHub OAuth application settings page.
  2. Set the Homepage URL to your production URL. E.g.
    https://hunt.deno.land.
  3. Set the Authorization callback URL to your production URL with the
    /callback path. E.g. https://hunt.deno.land/callback.
  4. Copy all the environment variables in your .env file to your production
    environment.

Deploy to Deno Deploy

  1. Clone this repository for your SaaSKit project.
  2. Update your .github/workflows/deploy.yml file as needed. Hints are in the
    file.
  3. Sign into Deno Deploy with your GitHub
    account.
  4. Click + New Project.
  5. Select your GitHub organization or user, repository, and branch.
  6. Click Edit mode and select Build step with GitHub Actions as the
    build mode and main.ts as the entry point.
  7. Click Add Build Step and wait until the GitHub Actions Workflow is
    complete.
  8. Once the deployment is complete, click on Settings and add the production
    environmental variables, then hit Save.

You should now be able to visit your newly deployed SaaS website.

Deploy to any VPS with Docker

Docker makes it easy to deploy and run your Deno app to
any virtual private server (VPS). This section will show you how to do that with
AWS Lightsail and Digital Ocean.

  1. Install Docker on your machine, which should also
    install
    the docker CLI.
  2. Create an account on Docker Hub, a registry for
    Docker container images.

Note: the Dockerfile, .dockerignore and
docker-compose.yml files come included with this
repo.

  1. Grab the SHA1 commit hash by running the following command in the repo's root
    folder:
sh
# get the SHA1 commit hash of the current branch git rev-parse HEAD
  1. Copy the output of the above and paste it as DENO_DEPLOYMENT_ID in your
    .env file. This value is needed to enable caching on Fresh in a Docker
    deployment.

  2. Finally, refer to these guides for using Docker to deploy Deno to specific
    platforms:

Set Up Stripe for Production (Optional)

  1. Activate your Stripe account.
  2. Navigate to the
    API keys page on the
    Developers dashboard.
  3. In the Standard keys section, click Reveal test key on the Secret
    key
    table row.
  4. Click to copy the value and paste to your STRIPE_SECRET_KEY environment
    variable in your production environment.
    bash
    STRIPE_SECRET_KEY=<Stripe secret key>
  5. Navigate to the Webhooks page to
    register your webhook endpoint.
  6. Click Add endpoint.
  7. Set Endpoint URL to your production URL with the /api/stripe-webhooks
    path. E.g. https://hunt.deno.land/api/stripe-webhooks.
  8. Set Listen to to Events on your account.
  9. Set customer.subscription.created and customer.subscription.deleted as
    events to listen to.
  10. Click Add endpoint.
  11. Optionally,
    set up your Stripe branding
    to customize the look and feel of your Stripe checkout page.

Google Analytics (Optional)

Set GA4_MEASUREMENT_ID in your production environment to enable Google
Analytics.

Note: it is not recommended to set this locally, otherwise your tests and
debugging requests will be logged.

REST API Reference

GET /api/items

Get all items in chronological order. Add ?cursor=<cursor> URL parameter for
pagination. Limited to 10 items per page.

Example 1:

jsonc
// https://hunt.deno.land/api/items { "values": [ { "id": "01HAY7A4ZD737BHJKXW20H59NH", "userLogin": "Deniswarui4", "title": "czxdczs", "url": "https://wamufx.co.ke/", "score": 0 }, { "id": "01HAD9KYMCC5RS2FNPQBMYFRSK", "userLogin": "jlucaso1", "title": "Ok", "url": "https://github.com/jlucaso1/crunchyroll-quasar", "score": 0 }, { "id": "01HA7YJJ2T66MSEP78NAG8910A", "userLogin": "BrunoBernardino", "title": "LockDB: Handle process/event locking", "url": "https://lockdb.com", "score": 2 } // 7 more items... ], "cursor": "AjAxSDdUNTBBUkY0QzhEUjRXWjkyVDJZSFhZAA==" }

Example 2 (using cursor field from page 1):

jsonc
// https://hunt.deno.land/api/items?cursor=AjAxSDdUNTBBUkY0QzhEUjRXWjkyVDJZSFhZAA== { "values": [ { "id": "01H777YG17VY8HANDHE84ZXKGW", "userLogin": "BrunoBernardino", "url": "https://asksoph.com", "title": "Ask Soph about a dead philosopher", "score": 2 }, { "id": "01H6RG2V3AV82FJA2VY6NJD9EP", "userLogin": "retraigo", "url": "https://github.com/retraigo/appraisal", "title": "Appraisal: Feature Extraction, Feature Conversion in TypeScript", "score": 0 }, { "id": "01H64TZ3TNKFWS35MJ9PSGNWE1", "userLogin": "lambtron", "url": "https://www.zaynetro.com/post/2023-how-deno-works", "title": "How Deno works (blog post)", "score": 2 } // 7 more items... ], "cursor": "AjAxSDJUSlBYWUJRM1g0OEo2UlIzSFgyQUQ0AA==" }

GET /api/items/:id

Get the item with the given ID.

Example:

jsonc
// https://hunt.deno.land/api/items/01H5379J1VZ7EB54KSCSQSCRJC { "id": "01H5379J1VZ7EB54KSCSQSCRJC", "userLogin": "lambtron", "url": "https://github.com/Savory/saaskit-danet", "title": "saaskit-danet: a modern SaaS template built for Fresh for SSR and Danet for the API", "score": 10 }

GET /api/users

Get all users in alphabetical order by GitHub login. Add ?cursor=<cursor> URL
parameter for pagination. Limited to 10 users per page.

Example 1:

jsonc
// https://hunt.deno.land/api/users { "values": [ { "login": "51chengxu", "sessionId": "9a6745a1-3a46-45c8-a265-c7469ff73678", "isSubscribed": false, "stripeCustomerId": "cus_OgWU0R42bolJtm" }, { "login": "AiridasSal", "sessionId": "adb25cac-9be7-494f-864b-8f05b80f7168", "isSubscribed": false, "stripeCustomerId": "cus_OcJW6TadIjjjT5" }, { "login": "ArkhamCookie", "stripeCustomerId": "cus_ObVcWCSYwYOnWS", "sessionId": "fd8e7aec-2701-44ae-925b-25e17ff288c4", "isSubscribed": false } // 7 more users... ], "cursor": "AkVob3ItZGV2ZWxvcGVyAA==" }

Example 2 (using cursor field from page 1):

jsonc
// https://hunt.deno.land/api/users?cursor=AkVob3ItZGV2ZWxvcGVyAA== { "values": [ { "login": "EthanThatOneKid", "sessionId": "ae7425c1-7932-412a-9956-e456787d557f", "isSubscribed": false, "stripeCustomerId": "cus_OeYA2oTJRlZBIA" }, { "login": "Fleury99", "sessionId": "2e4920a3-f386-43e1-8c0d-61b5e0edfc0d", "isSubscribed": false, "stripeCustomerId": "cus_OcOUJAYmyxZlDR" }, { "login": "FriendlyUser", "stripeCustomerId": "cus_ObLbqu5gxp0qnl", "sessionId": "508ff291-7d1c-4a67-b19f-447ad73b5914", "isSubscribed": false } // 7 more users... ], "cursor": "Ak5ld1lhbmtvAA==" }

GET /api/users/:login

Get the user with the given GitHub login.

Example:

jsonc
// https://hunt.deno.land/api/users/hashrock { "login": "hashrock", "stripeCustomerId": "cus_ObqbLXkRtsKy70", "sessionId": "97eec97a-6636-485e-9b14-253bfa3ce1de", "isSubscribed": true }

Goals and Philosophy

For the user, the website should be fast, secure and have a design with clear
intent. Additionally, the HTML should be well-structured and indexable by search
engines. The defining metrics for these goals are:

For the developer, the codebase should minimize the steps and amount of time
required to get up and running. From there, customization and extension of the
web app should be simple. The characteristics of a well-written codebase also
apply, such as:

  • Easy to understand
  • Modular functionality
  • Clearly defined behavior with validation through tests

Community and Resources

Join the #saaskit channel in Deno's Discord to meet
other SaaSKit developers, ask questions, and get unblocked.

Here's a list of articles, how to guides, and videos about SaaSKit:

Contributors

Showing top 12 contributors by commit count.

View all contributors on GitHub →

This article is auto-generated from denoland/saaskit via the GitHub API.Last fetched: 6/29/2026