Open-source project
KolbySisk/next-supabase-stripe-starter avatar
KolbySisk/next-supabase-stripe-starter

next-supabase-stripe-starter is a Next.js subscription app skeleton with the wiring done

The highest quality SaaS starter with Next.js, Supabase, Stripe, and shadcn/ui

817 stars163 forksTypeScriptMIT

At a glance

What is it?
next-supabase-stripe-starter combines Next.js 15, Supabase for Postgres and authentication, Stripe for checkout and subscriptions, shadcn/ui and Tailwind for the interface, and React Email with Resend for mail, with a nine step setup that ends with a working subscription flow in test mode. It is MIT licensed, the demo is deployed on Vercel, and the last push was on 2026-04-15.
Who is it for?
next-supabase-stripe-starter fits a developer who wants to ship a subscription product this week and would rather not spend that week wiring Stripe webhooks to a Postgres schema, since the synchronisation path, the fixture catalogue and the migrations are already written. It is the wrong choice for a team with an existing data model, a billing provider of its own or a need for usage based pricing, because the starter fixes the shape of the product around flat plans.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the repository gives you and what it does not

next-supabase-stripe-starter is described as a SaaS starter with Next.js, Supabase, Stripe and shadcn/ui, and the README's framing is deliberately practical: bootstrap your SaaS with a modern stack built to move quick.

The included list is specific enough to be useful. Next.js 15 is the framework. Supabase provides the Postgres database and user authentication. Stripe covers Checkout, subscriptions and the customer portal, with links to each of those docs. React Email builds the mail and Resend sends it. Tailwindcss is the CSS framework and shadcn/ui supplies prebuilt accessible components. Then the parts that are usually the slow bit: webhooks that automatically synchronise Stripe with Supabase, a Stripe fixture to bootstrap product data, Supabase migrations to bootstrap and manage the database schema, and responsive, performant, accessible prebuilt pages.

The last item on the list is the animated button borders, described with the joke that you can look cool without nerds saying you shipped too late. It is a small thing, and it is a useful signal about what kind of repository this is.

The dependency list in package.json shows the same picture in concrete form: the Radix UI primitives that shadcn/ui is built on, the Stripe JavaScript and server libraries, the Supabase JavaScript client and the SSR helper for cookie based sessions, React 19, React Email, Resend, lucide-react for icons and Vercel Analytics.

The project is MIT licensed, private in the package manifest, and the source is TypeScript with a components.json file for the shadcn/ui configuration.

Deploying to Vercel with a fixed list of environment variables

The deployment step is a Vercel clone button, and the environment variable list in that button is the contract between the three services the starter depends on.

The variables are NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY, SUPABASE_DB_PASSWORD, NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET and RESEND_API_KEY. The Supabase integration is added to the new project during the deploy form, and the README asks you to add the variables you already have, with the note that for the Stripe webhook secret you can put any value at this stage and come back to update it after configuring the webhook.

That last instruction is the right shape for a starter, and it is also a small trap for someone who deploys and then forgets, because a wrong webhook secret means the signature check fails on every event.

The flow after the deploy button is: create a new repository, add the Supabase integration, add the environment variables, deploy, then while it builds, clone your new repository, open it in your editor, create a file named .env.local, and copy the contents of .env.local.example into it with the correct values, which should match what you entered in the deploy form.

The repository carries .env.local.example at the root for exactly this purpose, and the .env.local file it creates is not committed, since .gitignore is present. The local and hosted environments are therefore configured separately, which is a reasonable arrangement as long as the two stay in step.

Stripe fixtures are the product catalogue, and the webhook mirrors it

The guide on managing products is where the design of this starter becomes clear.

Your products and prices are managed through the stripe-fixtures.json file rather than through the Stripe dashboard. The README explains that you can delete your test data on the Stripe Developers page, make the changes you want, and then run the fixture command again. When changes are made in Stripe, the webhook hits the API route at src/app/api/webhooks, and the handler synchronises the data Stripe sent into your Supabase database.

That is a genuinely opinionated choice. The usual way to run a Stripe product catalogue is to create it in the dashboard and let webhooks update your database. Here the fixture file is the source of truth for the product and price data, which means the catalogue lives in version control, gets reviewed in pull requests, and can be seeded into a fresh test environment with one command. The cost is that the file has to be edited by hand, with the prices and ids in it, and a mistake in it is a mistake in every environment you apply it to.

The scripts in package.json show the supporting commands. The stripe:listen script runs the Stripe CLI forwarding to localhost:3000/api/webhooks under a project name placeholder, which is how you receive events locally. The generate-types script regenerates the Supabase TypeScript types from the linked project's public schema, and the migration scripts create, apply and squash Supabase migrations.

The migration flow from the README is: log in with the Supabase CLI, initialise the project, replace the two placeholder strings for the Supabase project id in package.json, link the project and run the migration up command.

The nine step setup, and the password reset in the middle

The getting started section is nine numbered steps, and step one contains the detail that will save you an hour.

When you create a Supabase project, the README tells you to go to Project Settings, Database, Database password, and to reset the database password and generate a new one. The reason given is a bug in the Supabase CLI where it does not like special characters in the password, with a link to the issue. The recommendation is to save the password somewhere, because you cannot see it after closing the box.

The remaining service setup is three steps each. Stripe needs a project and the customer portal configured, with the test link button in Customer Portal Settings enabled so the portal works in test mode. Resend needs an account, an API key from the API Keys page, and the Supabase Resend integration added, so that Supabase can send mail through it.

Then come the two finishing steps that are easy to miss. The README asks you to do a Search All in your editor for UPDATE_THIS and update every instance with the relevant value, explicitly excepting .env.local.example, and to delete the delete-me directory, which holds the banner image and the deployment screenshot used in the README itself.

That search for UPDATE_THIS is a reasonable safety net, and it is also an admission that the repository ships with placeholders rather than configuration. There are at least four of them: the app name in package.json, the Supabase project id in two strings, the Stripe project name for the listen script and the Stripe secret key for the fixture command.

The test walkthrough, ending on a fake card number

The last section of the setup is a manual test of the whole path, and it is worth following exactly the first time because it exercises every moving part.

Install the dependencies and start the dev server.

bash
bun i
bun run dev

Then, in the app, click Get started for free, which takes you to the login page. Since no auth providers are configured, the README says to click Continue with Email and submit your email address, and then click the link that was sent to that address, which redirects back into the app authenticated. That is a magic link flow, and it is worth noting that the starter has no OAuth providers wired up, so email is the only path until you add some.

From there, click Get Started on one of the plans, which opens a Stripe checkout page in test mode. The card number to use is given in the README.

bash
4242424242424242

The rest of the form takes any valid data. After subscribing you should be redirected to the Account page with the new subscription shown, and the Manage your subscription button takes you into the customer portal, which is the piece that the test link step in Stripe was there to enable.

The lock file in the repository is bun.lockb, so Bun is the expected package manager, and the dev script runs next dev with the Turbopack flag.

Where a starter template is the wrong answer

Three situations argue against using this as a base.

The first is a team with an existing data model. The Supabase migrations bootstrap a schema, and the Stripe fixture assumes a catalogue of flat plans. If your product is usage based, has tiers with metered features, or has an entitlement model that does not map onto a product and a price, you will be rewriting the catalogue handling and the synchronisation handler rather than extending them. The README's guide covers managing products through fixtures, and that is the only product model it describes.

The second is a team that already has billing or authentication settled. If you have chosen a different payment provider, or you use an identity provider that your app must authenticate against, the Supabase and Stripe pieces are in the way rather than helpful. The authentication example is the clearest case, since the starter has no auth providers configured at all and the first test step is an email magic link.

The third is a team that needs a deployment story other than Vercel. The README's deploy button, the Supabase integration and the environment variable list are all Vercel shaped, and the project topics name Vercel explicitly.

For the narrow case it was built for, a small subscription product on Next.js with Postgres behind it, the work it saves is real, and the README is unusually complete for a starter, down to the fixture command and the local webhook forwarding. What a reader should weigh is the maintenance picture: the repository publishes no releases, and the last push was on 2026-04-15, so the dependencies in package.json will age faster than the code does.

Editorial conclusion

next-supabase-stripe-starter fits a developer who wants to ship a subscription product this week and would rather not spend that week wiring Stripe webhooks to a Postgres schema, since the synchronisation path, the fixture catalogue and the migrations are already written. It is the wrong choice for a team with an existing data model, a billing provider of its own or a need for usage based pricing, because the starter fixes the shape of the product around flat plans. Before you build on it, walk the setup in test mode end to end, read the webhook handler at src/app/api/webhooks, and replace the placeholder identifiers by searching for UPDATE_THIS, keeping in mind that the repository was last pushed on 2026-04-15 and publishes no releases.

Frequently asked questions

What is included in next-supabase-stripe-starter?

Next.js 15, Supabase for Postgres and user authentication, Stripe for Checkout, subscriptions and the customer portal, React Email with Resend for mail, Tailwindcss, shadcn/ui components, webhooks that synchronise Stripe with Supabase, a Stripe fixture for product data, Supabase migrations, and prebuilt responsive and accessible pages.

How do I set up Supabase, Stripe and Resend for the starter?

Create a Supabase project and reset the database password to a new one, because of a CLI bug with special characters, then create a Stripe project and enable the test link in Customer Portal Settings, then create a Resend account with an API key and add the Supabase Resend integration.

How are Stripe products and prices managed in this starter?

Through the stripe-fixtures.json file rather than the Stripe dashboard, with the fixture command applied to seed the data. When products change in Stripe, the webhook hits the route at src/app/api/webhooks and the handler synchronises the data into your Supabase database.

How do I run the Supabase migrations and the local test flow?

Log in and initialise the Supabase CLI, replace the placeholder project id in package.json, then run bun run supabase:link and bun run migration:up. Locally, run bun i and bun run dev, sign in with the email magic link, pick a plan and complete the Stripe test checkout with the card number 4242424242424242.

When was next-supabase-stripe-starter last updated?

The last push to the repository was on 2026-04-15, and the project publishes no GitHub releases, so there is no tagged version to pin and the dependencies in package.json will age faster than the code. The project is MIT licensed with a live demo deployed on Vercel.

Official sources

  1. Issues
  2. KolbySisk/next-supabase-stripe-starter on GitHub
  3. License: MIT
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/kolbysisk-next-supabase-stripe-starter.svg)](https://hysenlabs.com/projects/kolbysisk-next-supabase-stripe-starter)

Was this useful?