Vercel Deployment
Link the template to the correct Vercel project, configure Production values safely, deploy, and run bounded production checks.
See the hosted deployment status before using this deployment guide.
Deploy the single TanStack Start app to Vercel after the production Supabase project, the selected billing provider, and required environment values are ready. Use Stripe test mode for the hosted billing checks. For Polar, start with the local sandbox journey; hosted Polar on TanStack Start has not been verified. Vercel CLI owns project linking, environment configuration, and deployment.
Use the intended Vercel account, team, and project. Never put database URLs, API keys, signing secrets, or tokens in command arguments, terminal logs, or screenshots.
Deploy to production
Prepare hosted Supabase
Create or select the project in Supabase, then authenticate and link the checked-out template:
bunx supabase login
bunx supabase link --project-ref <project-ref>
bunx supabase db pushPut the hosted DATABASE_URL and the other required app values from the
selected Supabase project in ignored .env for local operator use.
Check the Vercel identity and project
Authenticate, inspect the current identity, and list projects in the intended account or team before linking:
bunx vercel login
bunx vercel whoami
bunx vercel teams lsFor a personal-account project, omit --scope. Vercel rejects a personal
username passed as a scope:
bunx vercel project ls
bunx vercel link --project <project-name>For a team project, use the team slug shown by teams ls:
bunx vercel project ls --scope <team-slug>
bunx vercel link --project <project-name> --scope <team-slug>If the identity, team, or project is wrong, stop before linking. Vercel writes ignored local link metadata. The provider CLI uses that link to select the project for later commands.
Keep the native build settings
The checked-in vercel.json selects the TanStack Start framework,
Bun 1.4.x for installation, and bun run build. Keep the project's Node.js
version at 24.x, its root directory at this repository root, and the
Output Directory override unset. The pinned Vercel CLI is available after
the root frozen install.
vite.config.ts uses Nitro's Vercel integration and explicitly selects
the Node.js 24 function runtime. Bun installs dependencies; Node runs the
production application. A managed build emits .vercel/output, including
static assets and the server function. Local Node builds emit .output.
Do not set Vercel's output directory to .output or publish only the
client assets: Auth, Hono, and server-rendered Docs need the server function.
See the official Start hosting guide and Vercel Bun configuration for the provider settings.
Add the Production environment
Open Supabase Settings → API Keys
and select Publishable and secret API keys. If an older project shows
Create new API keys, create the default key pair; the existing legacy
keys keep working while you migrate. Continue when both current keys are
visible. Use the publishable key for
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY and the server secret for
SUPABASE_SECRET_KEY.
Add public values with Vercel's interactive prompt:
bunx vercel env add NEXT_PUBLIC_APP_URL production
bunx vercel env add NEXT_PUBLIC_SUPABASE_URL production
bunx vercel env add NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY productionFor Polar, the hosted Polar setup describes the Next.js application and is reference-only for TanStack Start. It identifies server-only provider selection, sandbox offers, access token and hosted webhook secret; hosted Polar on TanStack Start has not been verified. A Polar-only app does not need Stripe settings. Keep existing Stripe settings for retained billing and outstanding deliveries.
For Stripe, add its public settings:
bunx vercel env add NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY production
bunx vercel env add NEXT_PUBLIC_STRIPE_MODE productionUse test for NEXT_PUBLIC_STRIPE_MODE during setup. Add the test account's
Price inputs only for the offers you sell from the
shared environment example.
Keep displayed amounts in src/config/pricing.config.ts aligned with Stripe.
These public inputs are embedded during the next build.
Add server values the same way. Mark secrets sensitive:
bunx vercel env add DATABASE_URL production --sensitive
bunx vercel env add SUPABASE_SECRET_KEY production --sensitive
bunx vercel env add RESEND_API_KEY production --sensitive
bunx vercel env add EMAIL_DELIVERY_MODE production
bunx vercel env add RESEND_FROM_EMAIL productionFor real application email, configure the Resend settings above. For Stripe
billing, also add its server secrets. Its automated guest checks use
EMAIL_DELIVERY_MODE=test_capture and a capture token instead of real delivery:
bunx vercel env add STRIPE_SECRET_KEY production --sensitive
bunx vercel env add STRIPE_WEBHOOK_SECRET production --sensitive
bunx vercel env add TEST_EMAIL_CAPTURE_TOKEN production --sensitiveThe CLI prompts for each value so secrets do not appear in argv. If a key already exists, update it without deleting it. Keep public updates readable, and mark every server-secret update sensitive:
bunx vercel env update NEXT_PUBLIC_APP_URL production
bunx vercel env update DATABASE_URL production --sensitive
bunx vercel env ls productionRepeat the first form for existing public keys and the --sensitive form
for existing server secrets.
For Stripe's automated guest checks, create TEST_EMAIL_CAPTURE_TOKEN in a
password manager before you paste it into the sensitive Vercel prompt, and
retain that same value for ignored
local .env. Vercel sensitive values cannot be read back after creation.
If the retained token is lost, update it from a new password-manager value,
deploy again, and replace the local copy before lifetime proof.
See Hosted Environment Variables for which values are public, server-only, proof-only, or required at launch.
Configure provider callbacks
In Supabase Dashboard → Authentication → URL Configuration, set the Site URL to the hosted app URL and add its redirect pattern.
For Polar, Create a hosted destination is a Next.js reference for the sandbox destination and event list, not verification of hosted TanStack Start. A hosted destination needs its own signing secret; the local listener secret does not apply.
For Stripe, in Dashboard test mode, create one webhook endpoint at
https://<project-name>.vercel.app/api/webhooks/stripe. Select these exact
events:
product.createdproduct.updatedproduct.deletedprice.createdprice.updatedprice.deletedcheckout.session.completedinvoice.paidcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deleted
Update STRIPE_WEBHOOK_SECRET in Vercel Production with that Stripe endpoint's
signing secret.
Deploy after Production values are complete
bunx vercel deploy --prodEnvironment changes apply to subsequent deployments. Deploy again after adding or updating a Production value.
Check liveness, Auth, and billing
Run the bounded route smoke first:
./coremvp prod e2e smoke https://<project-name>.vercel.appThis checks only /, /api/health, and /pricing. It does not prove Auth,
billing, callbacks, or webhook persistence.
The production proof CLI reads local values separately from Vercel. In a fresh checkout, restore readable Production values first:
bunx vercel env pull .env --environment=production
chmod 600 .envSensitive Vercel values cannot be read back. Treat every [SENSITIVE]
value as missing. In the next steps, replace the existing
SUPABASE_SECRET_KEY and TEST_EMAIL_CAPTURE_TOKEN assignments with
the real local values when the selected checks need them.
Keep exactly one assignment for each key; do not append duplicate lines
because the template CLI reads the first assignment.
In Supabase Dashboard, open Settings → API Keys → Publishable and secret
API keys for the project ref in NEXT_PUBLIC_SUPABASE_URL. Copy the
server secret into the existing SUPABASE_SECRET_KEY assignment in ignored
.env. Stop if the key is missing or belongs to a different project.
The capture steps below are for automated Stripe guest checks. The manual hosted sandbox checks describe Next.js and are reference-only for TanStack Start; hosted Polar has not been verified.
For Stripe guest proof, retrieve TEST_EMAIL_CAPTURE_TOKEN from the
password-manager item retained when the sensitive Vercel value was created
and paste it into ignored
.env. If it is unavailable, stop and rotate it through the Vercel prompt,
deploy again, and save the replacement. Verify the deployed capture mode
without sending or printing the token:
curl -sS -w '\nHTTP %{http_code}\n' https://<project-name>.vercel.app/api/testing/email-captures/onboardingExpected result: the app response
{"message":"Unauthorized","ok":false} followed by HTTP 401. Require
both markers because a provider or deployment-protection 401 does not
prove that the app route ran. An app response with HTTP 404 means
test_capture is disabled; correct the Vercel Production values and redeploy
before lifetime proof. The subsequent lifetime proof verifies that the
retained local token matches the deployment. Stop if the local Supabase
project or capture token does not match the deployed app.
Run Auth against the same exact URL:
export TEST_BASE_URL=https://<project-name>.vercel.app
export PROD_E2E_AUTH_MODE=signup
./coremvp prod e2e authThe hosted billing lanes currently exercise Stripe test mode only. For Polar, use the local sandbox journey and do not treat the Next.js reference as verification of the hosted path. For Stripe, continue:
export TEST_BASE_URL=https://<project-name>.vercel.app
unset PROD_E2E_AUTH_MODE
./coremvp prod e2e billing:lifetime
export PROD_E2E_AUTH_MODE=signup
./coremvp prod e2e billing:subscriptionCustom domain and live billing
Add the domain in Vercel, follow the DNS records Vercel provides, then update
the Supabase Site URL and Redirect URLs. Update NEXT_PUBLIC_APP_URL in Vercel
Production and deploy again before running the smoke, Auth, and billing checks
against the custom domain.
Hosted Polar on TanStack Start has not been verified. Complete the local Polar sandbox journey and stop before live activation until the hosted path is verified. Launch Your App is a Next.js reference, not evidence of native hosted Polar support.
Only after the Stripe hosted test path passes should you prepare live Stripe billing.
For Stripe, create the live Stripe objects
and live webhook endpoint. Set NEXT_PUBLIC_STRIPE_MODE=live and replace the
sold offers' catalog inputs and Stripe credentials with matching live values.
Unmapped offers remain unavailable in live mode; use a matching live secret key. Set real email
delivery values, remove proof-only values such as
TEST_EMAIL_CAPTURE_TOKEN, deploy again, and send a real transactional email
before launch.
Preview deployments
Preview is not part of the beginner production path. Do not point an arbitrary feature-branch preview at production Supabase, billing credentials, or webhook secrets. Use Hosted Environment Variables for the shared input block and the values to change for Preview.
Was this page helpful?