GitHub Repository
Minimal Next.js, Supabase, and Dodo Payments subscription boilerplate.
Live Demo
Explore the deployed demo.
Overview
The Supabase subscription starter is a Next.js 15 and React 19 app that sells subscriptions with Dodo Payments. Supabase provides Google OAuth sign-in and the Postgres database, and Drizzle ORM defines the schema. A Supabase Edge Function receives Dodo Payments webhooks and stores payments and subscriptions, and a basic dashboard shows each user’s plan and invoices. If you need only checkout, Customer Portal, and webhook route handlers for an existing app, use a framework adaptor instead:Next.js Adaptor
Express Adaptor
Prerequisites
Before you begin, you need:- Node.js 18 or later, or Bun 1.0 or later.
- A Supabase project. You need its URL, anon key, service role key, and database connection string.
- A Dodo Payments account, for an API key and a webhook signing secret.
- A Google Cloud OAuth client, for its Client ID and Client Secret.
Quickstart
1
Clone and Install
Clone the repository, then install dependencies with Bun, npm, or pnpm:
2
Create a Supabase Project
Create a Supabase project. Later steps use its project reference, the subdomain in
https://[your-project-ref].supabase.co. Copy these values:NEXT_PUBLIC_SUPABASE_URL, the project URLNEXT_PUBLIC_SUPABASE_ANON_KEY, the anon keySUPABASE_SERVICE_ROLE_KEY, the service role keyDATABASE_URL, the database connection string
3
Configure Google OAuth
In Google Cloud, add this authorized redirect URI to your OAuth client:
https://[your-project-ref].supabase.co/auth/v1/callback. Then, in Supabase Auth, enable the Google provider with your Client ID and Client Secret.4
Configure Dodo Payments
With the Live Mode switch in the sidebar off, create an API key under Developer → API Keys in the Dodo Payments dashboard. Keep
DODO_PAYMENTS_ENVIRONMENT set to test_mode while you develop.5
Add the Webhook in Dodo Payments
Under Developer → Webhooks, add an endpoint with this URL. You deploy the function that serves it in a later step.Select the payment and subscription events that the function handles:
- Payment events:
payment.succeeded,payment.failed,payment.processing, andpayment.cancelled - Subscription events:
subscription.active,subscription.plan_changed,subscription.renewed,subscription.on_hold,subscription.cancelled,subscription.expired, andsubscription.failed
DODO_WEBHOOK_SECRET.6
Create .env.local
Create a The Next.js app reads every variable in this file except
.env.local file in the root directory:DODO_WEBHOOK_SECRET. The Edge Function reads DODO_WEBHOOK_SECRET from its Supabase secrets, which you set when you deploy it.7
Provision the Database Schema
Push the Drizzle schema to your Supabase database:
Tables created:
users, subscriptions, payments.8
Deploy the Webhook Function
Log in to Supabase, store the signing secret as a function secret, and deploy the The A
dodo-webhook Edge Function. Replace [your-project-ref] with your project reference:deploy:webhook script runs supabase functions deploy dodo-webhook --no-verify-jwt, so Dodo Payments can call the function without a Supabase auth token. Supabase provides SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY to the function by default.To check the deployment, send an unsigned request:cURL
400 response with Invalid webhook signature means the function is running and has its secret. A 500 response with Server configuration error means DODO_WEBHOOK_SECRET isn’t set. To send a signed test event, open the endpoint in Developer → Webhooks and use its Testing tab.9
Create Products and Features
Under Products in the Dodo Payments dashboard, click Add Product to create a subscription product for each plan. Optionally, to list plan features in the app, add a metadata entry with the key Metadata values are strings, numbers, or booleans, so store the array as a JSON string. The pricing UI parses the
features and a JSON array of strings as its value. The product’s metadata then looks like this:features value and renders each item.10
Run the Dev Server
You now have a working subscription SaaS scaffolded with Supabase and Dodo Payments. To confirm it end to end, subscribe to a plan with a test card. After the webhook arrives, the dashboard shows your new plan.
What’s Included
- Authentication through Supabase, with Google OAuth configured
- Subscription checkout through Dodo Payments
- A Supabase Edge Function for webhooks (
dodo-webhook) - A Drizzle ORM schema, with
db:generateanddb:migratescripts for migrations - A dashboard with invoices, subscription status, and plan features
- Server actions to change plans, cancel a subscription, and restore a cancelled subscription
Key Files and Paths
The webhook handler, app routes, and database schema live in these files:- Edge Function
- Next.js Routes
- Database (Drizzle)
Environment Variables
The Next.js app and the Edge Function read these variables:Supabase
Supabase
.env.example doesn’t list SUPABASE_SERVICE_ROLE_KEY, but the app’s admin client in lib/supabase/admin.ts needs it. Add it yourself.Dodo Payments
Dodo Payments
Google OAuth
Google OAuth
The app doesn’t read Google credentials from environment variables. Enter the Client ID and Client Secret in the Google provider settings of Supabase Auth, and add this redirect URI to the OAuth client in Google Cloud:
Verification and Troubleshooting
Webhook signature invalid (400)
Webhook signature invalid (400)
- Make sure the function’s
DODO_WEBHOOK_SECRETsecret matches the endpoint’s signing secret in the Dodo Payments dashboard. - Confirm you deployed the latest
dodo-webhookfunction. - The function verifies the Standard Webhooks headers
webhook-id,webhook-signature, andwebhook-timestamp. Make sure a proxy doesn’t strip them.
Database push fails
Database push fails
- Check the
DATABASE_URLsyntax. - The direct connection (
db.[project-ref].supabase.co:5432) uses IPv6 unless your project has the IPv4 add-on. On an IPv4-only network, use the session pooler connection string instead (Supabase connection docs). - Wait 2–3 minutes after you create the project before the first push.
OAuth redirect mismatch
OAuth redirect mismatch
- The redirect URI must be
https://[ref].supabase.co/auth/v1/callback. - Use the same URI in Google Cloud and in the Supabase Auth provider.
For the original repository and detailed steps, see dodo-supabase-subscription-starter.