Bootstrap your SaaS with a modern tech stack built to move quick. Follow the guide to get started.
Active test link
button.env.local
. Copy and pase the contents of .env.local.example
into this file and add the correct values. They should be the same values you added in above.Developers
in the top nav, and then the Webhooks
tab/api/webhooks
Select events
Select all events
Add endpoint
Reveal
signing secret and copy itVercel project settings
→ Environment Variables
STRIPE_WEBHOOK_SECRET
env with your newly acquired webhook secret. Press Save
Now we're going to run the initial Supabase Migration to create your database tables.
npx supabase login
npx supabase init
package.json
and update both UPDATE_THIS_WITH_YOUR_SUPABASE_PROJECT_ID
strings with your supabase project idnpm run supabase:link
npm run migration:up
Stripe fixtures are an easy way to configure your product offering without messing around in the Stripe UI.
brew install stripe/stripe-cli/stripe
stripe fixtures ./stripe-fixtures.json --api-key UPDATE_THIS_WITH_YOUR_STRIPE_SK
Search All
in your code editor for UPDATE_THIS
and update all instances with the relevant value (except for .env.local.example!)delete-me
dirYou did it! You should be able to look in your Stripe dashboard and see your products, and you should also see the same data has been populated in your Supabase database. Now let's test everything.
npm i
npm run dev
.Get started for free
- this will take you to the login pageContinue with Email
and submit your email addressGet Started
on one of the plans. This will take you to a Stripe checkout page (In test mode)4242424242424242
as your credit card number. Fill out the rest of the form with any valid data and click SubscribeManage your subscription
buttonThat's the end of the setup. The following are guides to help you code in your new codebase.
Your products and prices are managed via the stripe-fixtures.json
file. You can delete your test data in Stripe on the Developers page, make the changes you'd like, and then run the fixture command from above. When changes are made in Stripe the webhook hits the api route at src/app/api/webhooks
. The handler will synchronize the data sent from Stripe to your Supabase database.
The metadata
field in your fixture is where we can store info about the product that can be used in your app. For example, say you have a basic product, and one of the features of the product includes a max number of team invites. You can add a field to the metadata like team_invites
. Then update the Zod schema in src/features/pricing/models/product-metadata.ts
Then you can make use of it like this:
const products = await getProducts();
const productMetadata = productMetadataSchema.parse(products[0].metadata); // Now it's typesafe 🙌!
productMetadata.teamInvites; // The value you set in the fixture
Migrations are a powerful concept for managing your database schema. Any changes you make to your database schema should be done through migrations.
Say you want to add a table named invites
.
First run npm run migration:new add-invites-table
Then edit your file to include:
create table invites (
id uuid not null primary key default gen_random_uuid(),
email text not null,
);
alter table invites enable row level security;
Then run npm run migration:up
and your table will be added.
There are many auth providers you can choose from. See the Supabase docs for the full the list and their respective guides to configure them.
Your emails live in the src/features/emails
dir. Emails are finicky and difficult to style correctly, so make sure to reference the React Email docs. After creating your email component, sending an email is as simple as:
import WelcomeEmail from '@/features/emails/welcome';
import { resendClient } from '@/libs/resend/resend-client';
resendClient.emails.send({
from: 'no-reply@your-domain.com',
to: userEmail,
subject: 'Welcome!',
react: <WelcomeEmail />,
});
The file structure uses the group by feature
concept. This is where you will colocate code related to a specific feature, with the exception of UI code. Typically you want to keep your UI code in the app
dir, with the exception of reusable components. Most of the time reusable components will be agnostic to a feature and should live in the components
dir. The components/ui
dir is where shadcn/ui
components are generated to.
Follow these steps when you're ready to go live:
If you need help with the setup, or developing in the codebase, feel free to reach out to me on Twitter @kolbysisk - I'm always happy to help.
PRs are always welcome.
This project was inspired by Vercel's nextjs-subscription-payments.