skt Svelte Themes

Skt

SvelteKit SaaS Boilerplate

SvelteKit Boilerplate for SaaS / WebApps

SKT ("SvelteKit Template") is a boilerplate for SaaS or web apps. The project is based on Svelte 5 and uses SvelteKit, Tailwind / DaisyUI, Supabase (Auth and DB) and Stripe. SKT is fully responsive with a mobile first design and supports light and dark mode, see below for screenshots.

The project is divided in two main routes, public and private. The public route is the front facing part, ie. the content people see when they visit your website, example.com. The private route is only accessible to logged-in users and resides at example.com/app. This is where registered users can edit their profile, manage their subscription and access the actual app or SaaS. The boilerplate will only show a placeholder in lieu of the app.

Installation

Clone or download repo and install dependencies:

npm install

Setup .env

Copy .env.example to .env.local. You will have to provide the following info and keys:

# Project

PUBLIC_PROJECT = 'Your Projects Name'

# Supabase

PUBLIC_SUPABASE_URL = 'https://YOURPROJECT.supabase.co'
PUBLIC_SUPABASE_ANON_KEY = ''
PRIVATE_SUPABASE_SERVICE_ROLE = ''

# Stripe

PUBLIC_DOMAIN = 'http://localhost:5173'
PUBLIC_STRIPE_CUSTOMER_PORTAL = ''
PUBLIC_STRIPE_API_KEY = ''
PRIVATE_STRIPE_API_KEY = ''
PRIVATE_STRIPE_WHSECRET = ''

Stripe's WHSecret key is optional; the webhook is implemented at $src/routes/(admin)/webhooks/stripe/+server.ts but currently unused as we use Stripe's embedded checkout, see below.

Setup Supabase

Create a project in Supabase and make a note of the project URL and keys; you will need to add both the ANON and the SERVICE ROLE key to .env.local. SKT uses Supabase Auth. Two additional public tables are needed for user management: "Users" and "Profiles". In your project, open the SQL Editor and run supabase.sql to set up the tables and triggers.

Currently supported is signing up per email / password and Google OAuth. Enable both providers in Supabase > Authentication > Providers. In SKT, all relevant code resides in $src/routes/(admin)/auth.

Email / Password auth

For email leave everything at defaults (disabling "Confirm email" speeds things up during development). Note that changing the user's email is currently not supported.

Google OAuth

To setup Google OAuth you can follow Supabase's walkthrough. You can ignore the code samples in the walkthrough, all of this is already built-in. Or follow these steps:

In Authentication > Providers, open the Google dropdown and make a note of the callback URL, you will need it in step #7 below. Client ID and Client secret will be filled in at step #12.

In Google Cloud, setup a project, then navigate to Google Auth Platform and click "Get Started". Then:

  1. Provide the app name and support email
  2. For audience, select "External"
  3. Provide a contact email and agree to TOS
  4. In the sidebar, select "Clients" and click "Create Client"
  5. For application type, select "Web application" and give it a name
  6. In "Authorized JS origins", enter http://localhost (in production also add your real domain)
  7. In "Authorized redirect URIs", enter the callback URL. It will be of the form https://YOURPROJECT.supabase.co/auth/v1/callback
  8. Click "Create".
  9. The client will now be listed. Click it to open the configuration and make a note of the "ClientID" and the "Client secret"
  10. In the sidebar, select "Data Access".
  11. Click "Add or remove scopes" and select ".../auth/userinfo.email" from the list, then "Save"
  12. Finally, back in Supabase enter the Client ID and secret into the Google dropdown.

Setup Stripe

Note: This assumes that you are working in Stripe's test mode.

Stripe API keys

In your Stripe dashboard, make a note of the API keys. You need to add both the public and the private key to your .env.local file (the keys should begin with "pk_test" and "sk_test"). To have the user manage their subscription, enable the customer portal here and add the URL to .env.local.

Stripe Products

SKT assumes three tiers (named "Free", "Core" and "Pro" in the boilerplate). The "Core" and "Pro" tiers feature monthly or yearly billing. Newly registered users default to the "Free" tier so only the other two have to be setup in Stripe. Create two products with two prices each, one for a monthly payment, one for a yearly payment. Make a note of the respective product IDs ("prod...") and price IDs ("price...").

Modify the table in $lib/utility/plans.ts to represent your products. You will need to provide all details, like so:

{
    id: 'core',
    name: 'Core',
    description: 'Core plan description.',
    popular: 'true',
    price: ['$9.99', '$99.99'],
    priceIntervalName: ['monthly', 'yearly'],
    priceId: ['price_1QSdXlEIoDgScXMg0KHwWiDH', 'price_1QSdXlEIoDgScXMgrEfsS170'],
    productId: 'prod_RLKCfgua9ZWSiN',
    features: ['Everything in Free', 'Core Feature 1', 'Core Feature 2']
}

The data will be pulled from the table and properly formatted. The relevant code lives at $src/(public)/(subscription)/pricing and in $lib/components/PlanCard. Note that the pricing table is dynamic; the button text and destinations change depending on the status of the user. Modify the logic for your use case in PlanCard.svelte, for example if you want to offer upgrades from one tier to a higher one.

Stripe Webhooks

SKT integrates Stripe's embedded checkout (see $src/routes/(public)/(subscription)checkout). Once the payment is completed, Stripe's plugin redirects to $src/routes/(public)/(subscription)/subscribed. The code then updates the "Users" table and simply shows a Thank you-note, redirecting the new subscriber to the private section of the site. When a registered user accesses the private section, the code in $src/routes/(private)/app/+layout.server.ts checks with Stripe if the subscription is still active and updates the status accordingly. It's up to you to handle status changes, e.g. to restrict features of your app when a subscription has been deleted or is past due.

In this scenario, webhooks are not required. However, it can be useful to capture additional Stripe subscription events via webhooks. Enable webhooks in the Stripe dashboard and select the events you are interested in. Make a note of the webhook's secret ("whsec...") and add it to .env.local. You will have to provide a publicly accessible URL as a destination. The webhook endpoint sits at $src/routes/(admin)/webhooks/stripe. When live on the web the destination URL would be example.com/webhooks/stripe. In development on localhost, you will need a service like ngrok to make this URL available to the outside.

Tip: Use the Stripe CLI to generate events locally.

Run

Run the project with:

npm run dev

Then, in your browser, navigate to http://localhost:5173.

Credits

Svelte

Svelte Dev

Tailwind

Tailwind CSS

DaisyUI

Daisy UI

Icons

HeroIcons

Stripe Integration

Based on SvelteKit Stripe Demo

License

MIT.

Screenshots

SKT SvelteKit Saas Boilerplate Website

SKT SvelteKit Saas Boilerplate Sign In

SKT SvelteKit Saas Boilerplate Pricing

SKT SvelteKit Saas Boilerplate App

SKT SvelteKit Saas Boilerplate Profile

SKT SvelteKit Saas Boilerplate Dark Mode

Top categories

Loading Svelte Themes