How to deploy a Next.js SaaS to Vercel with Supabase
Deploy a Next.js app to Vercel with Supabase, migrations, authentication redirects, and verified billing webhooks.
Deploying a Next.js SaaS means connecting the deployed code to the right database and authentication project, applying its schema safely, and verifying the public purchase and access paths. A successful Vercel build only proves that a build completed; it does not prove sign-in or payment fulfillment.
This example uses a Next.js App Router repository, Supabase Auth and Postgres, Vercel, and optionally Stripe subscriptions. It assumes you own the accounts and have a working local app. If you use CoreMVP, follow its deployment Docs for the template's exact commands and configuration; do not substitute generic migration commands for its migration owner.
Before you start
Have your app in a Git repository connected to Vercel, a separate Supabase project for production, a public domain or Vercel production URL, and access to the accounts that administer them. For billing, also have a Stripe sandbox and a working test Checkout, signed webhook handler and durable access reader. How to add authentication to Next.js and how to add Stripe billing to Next.js describe the application boundaries.
For the concrete migration commands below, the app must use the Supabase CLI's directory as its schema source. If your app uses Drizzle or another migration system, use that tool's documented deployment procedure instead; do not apply two independent migration histories to the same schema. Review the migrations and row-level security policies, test them on a separate staging database, and have a backup and recovery plan before touching an existing production database. Supabase explains database migrations and environment separation.
1. Inventory the source and environment
Read your repository's package scripts, lockfile, environment example and migration directory. Identify the app root, install and build commands, Supabase callback route, webhook route, and every server or public configuration name. For the examples in the linked auth and billing guides, the names include:
| Name | Purpose | Exposure |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL | Supabase project URL | Browser-visible |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY | Supabase publishable key | Browser-visible; use RLS and authorization |
APP_URL | Public origin used by the example billing redirects | Server configuration |
STRIPE_SECRET_KEY | Stripe server API key | Secret, server only |
STRIPE_WEBHOOK_SECRET | Signing secret for the specific webhook endpoint | Secret, server only |
These names are examples, not a universal schema. Use the names your own code actually reads, including any database connection or email settings it requires. Never prefix a service-role key, database password or Stripe secret with NEXT_PUBLIC_: Next.js embeds public variables in browser bundles at build time. See Next.js environment variables.
Run your repository's normal local build and tests against non-production services first. Confirm protected pages and direct API requests reject anonymous and unauthorized users. A public Supabase key is designed for client use; it is not a replacement for correct database policies.
2. Prepare and migrate Supabase
Create or select the intended production Supabase project and verify its project reference in the Dashboard. Confirm that it is the target before linking the CLI. For a project whose migrations are owned by , run these commands from the repository root with the installed Supabase CLI, replacing the placeholder with the exact intended project reference:
supabase login
supabase link --project-ref YOUR_PROJECT_REF
supabase migration list
supabase db push --dry-runCompare the linked project and remote migration history with the reviewed files. The dry run should list only the intended pending migrations. Stop if the target, history, or proposed SQL is unexpected. After reviewing the changes and preparing recovery, apply them:
supabase db push
supabase migration listConfirm the expected migrations now appear in the remote history and inspect the resulting tables and policies. db push changes the remote database; it is not part of a Vercel build. Supabase documents the link and migration workflow and the --dry-run option. Never use a remote database reset as a deployment shortcut.
3. Configure the Vercel project
Import the repository in Vercel, select the correct root directory and Next.js framework settings, and verify the detected build command against your source. In Project Settings, add the actual environment variable names identified in step 1 to the appropriate Production or Preview environment. Use the production Supabase URL and publishable key only for the intended production deployment. Keep preview deployments on separate test resources where possible, especially for writes and billing.
Set APP_URL, if your app uses it, to the public production origin with the correct scheme. Configure secrets through Vercel's environment settings rather than committing values. Vercel's environment documentation explains environment targeting: changes apply to new deployments, so redeploy after changing a value. NEXT_PUBLIC_* values are embedded during the build and likewise require a new build.
Deploy a preview using the repository's non-production branch and test resources first. Vercel describes preview and production deployments; a preview URL is a separate deployment and should not be assumed to use production configuration.
4. Configure authentication URLs
In the production Supabase Auth URL configuration, set the Site URL to your actual public origin and add the exact callback URLs your app uses, such as https://example.com/auth/callback. Add only the preview and local URLs you intend to support. Supabase's redirect URL guide describes allow lists and preview patterns.
For Google OAuth, Google's authorized redirect URI is the Supabase project's provider callback; the app callback is separately allowed in Supabase. Check both in the Google provider guide. Make sure confirmation and password-reset links return to the correct public site, and configure an appropriate email provider for real users under Supabase's production SMTP guidance. Do not log email links or secrets.
5. Configure and test webhooks
If the app sells through Stripe, first test the deployed preview against sandbox products, sandbox keys and a sandbox webhook destination. Register the publicly reachable HTTPS URL for your actual webhook route, select the event types your handler needs, and set that destination's signing secret in the same Vercel environment as the app. Redeploy so the secret is available. Stripe's webhook setup guide explains registered endpoints, signature verification and delivery inspection.
Complete a real sandbox Checkout through the deployed app. Verify a successful signed delivery, the correct customer and subscription in your test database, and paid access for the intended user. Resend the same event and verify no duplicate effects; cancel the subscription and verify access follows your policy. Do not use a synthetic event alone as proof of the purchase path. For production, configure the separate live price, key and live webhook destination only when you are ready to accept real payments. Never point a test listener's signing secret at the hosted live endpoint.
6. Release and verify the public app
Deploy the reviewed commit to Vercel Production using your project's normal Git deployment workflow. Confirm the deployment succeeded and the intended domain points to it. Then check:
- Public pages load at the production domain, with no secrets in client output or logs.
- A test account can sign up, complete email confirmation, sign in, reload and sign out; an anonymous request cannot read protected content.
- OAuth and password recovery return to the intended origin, if enabled.
- An authorized user can read and change their own data, while another user cannot access it through a page, API route or direct database policy.
- The billing test from step 5 passes in the intended non-production environment. For live billing, verify the live destination is configured and monitor delivery and reconciliation using your release procedure; sandbox proof is not live payment proof.
If a check fails, inspect Vercel deployment logs, the selected environment's configuration, Supabase Auth logs and Stripe delivery details as appropriate. Fix the responsible setting or code, redeploy when configuration changes require it, and repeat the failed path. Record which environment and account you tested.
CoreMVP's Next.js Docs provide a shipped authentication and billing foundation and its product-specific deployment instructions. They reduce the integration work you have to assemble, but your own domain, credentials, policies and provider configuration still need verification.