Nextbase Docs
Nextbase Docs
HomeBlogWelcome to Nextbase v5!Choose your starterGetting startedLocal Supabase per agent
TanStack + SupabaseInstallationEnvironment variablesAuthenticationAgent connectionsProject structureDeployment
AuthenticationWorkspaces and the admin area
Building with agentsEmails with Resend
TroubleshootingNextbase v5
The 8 starter kitsTanStack + Supabase

Deployment

Provision Supabase, apply the migrations and publish the TanStack + Supabase starter's web and admin apps to Vercel or any Node 24 host.

The kit deploys as two Node 24 Express servers: the product (apps/web) and the administration app (apps/admin). Both share one Supabase project. The live demo runs each on its own Vercel project, and the repository ships the packaging for that, but any platform that can run a Node 24 process behind a TLS proxy works. Follow the Vercel deployment guide for the platform-generic steps; this page lists what is specific to this kit. The repository's deployment.md and docs/admin-app.md have the same material in their own words.

1. Provision Supabase

Create a project in the Supabase dashboard and note the project ref, API URL, anonymous key and service-role key.

Link the CLI and push the migrations from apps/database:

cd apps/database
pnpm exec supabase link --project-ref <project-ref>
pnpm exec supabase db push

This includes 20261014114357_user_admin_mcp.sql, which creates mcp_records and the two service-only functions the MCP servers need. Apply it before the apps go live, or agent connections will fail. The seed file is not applied by db push; never load the local test accounts into production.

Then in the dashboard, under Auth and URL Configuration:

  • Set Site URL to the web app's APP_URL (the product origin).
  • Add Redirect URLs for /auth/callback and /auth/confirm on the web origin and again on the admin origin. These are the only auth routes registered in apps/web/src/routes.ts and apps/admin/src/routes.ts.
  • Configure SMTP for confirmation, magic-link and recovery emails. See emails with Resend. The apps' RESEND_API_KEY does not cover these.
  • Enable social providers only if you add provider buttons to the apps; the current login and sign-up pages offer password and magic link only.

If you want the admin JWT claim refreshed by the access-token hook, enable custom_access_token_hook in the project's Auth hooks. The function already exists after db push. It is optional: make_user_app_admin writes the claim directly.

2. Production environment variables

Set these in each deployment's secret manager. Names must match apps/web/.env.example and apps/admin/.env.example; see environment variables for the full list.

VariableWeb appAdmin app
NODE_ENVproductionproduction
APP_URLThe product origin, for example https://app.example.com. No path, query, hash or credentials.The admin origin, for example https://admin.example.com.
WEB_APP_URLNot usedThe product origin (the web app's APP_URL). Required for /health/ready; used for support sign-in links.
SUPABASE_URLThe project's API URL.Same value.
SUPABASE_ANON_KEYThe project's anonymous key.Same value.
SUPABASE_SERVICE_ROLE_KEYThe project's service-role key. Server-only.Same value.
HOST, PORTWhere Express binds on a Node host, for example 0.0.0.0 and 3000. Not used on Vercel.Same, for example 0.0.0.0 and 3002.

APP_URL matters more than it looks: it is the only origin accepted for form actions behind the proxy (isCanonicalOriginRequest), the origin for auth email links, and the issuer and resource for that app's MCP server (${APP_URL}/oauth plus ${APP_URL}/mcp/user on web or ${APP_URL}/mcp/admin on admin). A preview deployment with a different origin needs its own APP_URL and its own Supabase redirect URL entries. The demo follows the repository's <subdomain>-admin.usenextbase.com pattern for the admin origin.

Add optional integration variables as you turn features on: STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET (set them on admin too if you use its billing pages); RESEND_API_KEY and EMAIL_FROM (plus EMAIL_REPLY_TO); API_KEY_PEPPER with at least 32 random characters and API_CORS_ORIGIN; OPENAI_API_KEY with OPENAI_CHAT_MODEL and OPENAI_IMAGE_MODEL; ANALYTICS_ENABLED=true with POSTHOG_KEY. Server secrets must never get a public-variable prefix.

3. Build

From the repository root:

pnpm install
pnpm build

pnpm build builds every app through Turborepo. Each app build runs react-router build, bundles the Express entry with tsup to dist/index.js, boots that server and posts to a sign-in route from a foreign origin as a CSRF smoke test (scripts/check-built-auth.mjs, expecting 400), then packages a Vercel Build Output in .vercel/output (scripts/package-vercel.mjs). The packaging step traces the runtime files with @vercel/nft, refuses to include any .env* file, writes a nodejs24.x function with the app's index.mjs as the handler, and runs the smoke test again against the packaged bundle. Use pnpm web#build or pnpm admin#build to build one app.

Outputs per app (apps/web and apps/admin):

  • build/client: static assets
  • build/server: React Router server bundle
  • dist/index.js: Express entry point
  • .vercel/output: Vercel Build Output API v3 bundle

4. Deploy

Both apps ship a vercel.json with "framework": null and "buildCommand": "pnpm build", and an index.mjs that wraps the Express app for the Vercel function. When VERCEL is set, server/index.ts exports the app instead of calling listen, and the server trusts one proxy hop.

Create two Vercel projects from the same repository. Set the root directory of one to apps/web and of the other to apps/admin so each picks up its own vercel.json, and keep access to the workspace source enabled so pnpm build can resolve the shared packages. Map the product domain to the web project and the admin domain to the admin project. Add the environment variables from step 2 to each project (HOST and PORT are not needed), deploy, and confirm the logs show the packaging step completing. The function runtime is nodejs24.x, which matches .nvmrc.

Any platform that runs Node 24 containers and exposes TCP ports works (Fly.io, Railway, Render, AWS ECS and similar). Run one service per app:

  1. Use Node 24.
  2. Run pnpm install and pnpm build in the build phase (or pnpm web#build / pnpm admin#build).
  3. Start the web app with pnpm --filter web start and the admin app with pnpm --filter admin start; each runs NODE_ENV=production node dist/index.js in its own directory.
  4. Map each service's public HTTPS origin to its APP_URL, set the admin service's WEB_APP_URL to the web origin, and terminate TLS at the proxy.
  5. Point health checks at /health/live and /health/ready on both services.

5. Make yourself an administrator

Sign up on the deployed web app and confirm the email. Then, from the Supabase SQL editor:

select public.make_user_app_admin('<your user uuid>');

Sign out and in again, then open the admin origin's /login and /admin. Details are on the authentication page.

6. Stripe webhook (optional)

Add a webhook endpoint in Stripe pointing to ${APP_URL of web}/api/stripe/webhook and copy its signing secret to STRIPE_WEBHOOK_SECRET. Billing pages show a disabled state until STRIPE_SECRET_KEY is set.

7. Smoke checks

  • GET /health/live on both origins returns 200 with { "status": "ok" }.
  • GET /health/ready on both origins returns 200 with { "status": "ready" }. A 503 means one of APP_URL, SUPABASE_URL, SUPABASE_ANON_KEY or SUPABASE_SERVICE_ROLE_KEY is missing, or WEB_APP_URL on the admin app.
  • Open /login and /sign-up on the web app, create a test account, confirm its email, accept the terms and create a workspace. Add a project.
  • Test a password reset. Check that links return to your origin, not to localhost.
  • Open /mcp/connections/user on the web app and confirm the server address shows your web APP_URL. GET ${APP_URL}/mcp/user without a token should return a 401 challenge; GET ${APP_URL}/.well-known/oauth-protected-resource/mcp/user should return JSON. Connect an agent following connect an agent and call projects_list.
  • As an administrator, sign in on the admin origin, open /admin and /mcp/connections/admin, and generate a support sign-in link from /admin/users to confirm it lands on the web app's /auth/confirm.
  • Run pnpm check on the commit you deployed.

See troubleshooting if login returns to the wrong page or the MCP endpoint rejects an approved agent.

Project structure

The TanStack + Supabase monorepo layout and where to make common changes.

Next.js + Convex

Overview of the Next.js + Convex starter: what it ships, what you need, and where to go next.

On this page

1. Provision Supabase2. Production environment variables3. Build4. Deploy5. Make yourself an administrator6. Stripe webhook (optional)7. Smoke checks