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

Environment variables

Every variable in apps/web/.env.example and apps/admin/.env.example, what it does and where its value comes from.

This kit has two env files, one per deployable app: apps/web/.env (from apps/web/.env.example) and apps/admin/.env (from apps/admin/.env.example). Each Express server loads its own file with dotenv at startup, and src/.server/env.ts in each app validates the core values with Zod. Optional integrations are read lazily by src/.server/integrations.ts and stay disabled when their variables are empty.

The two example files are identical except for the admin app's PORT, APP_URL and the extra WEB_APP_URL. pnpm supabase:sync-env writes the three Supabase values into both files.

Never commit either .env file. The Vercel packaging scripts refuse to bundle any .env* file, and .gitignore excludes everything except the examples.

Public versus server-only

Nothing in these files is inlined into the browser bundle by Vite. The servers pass SUPABASE_URL and SUPABASE_ANON_KEY to the browser through loader data for realtime subscriptions, so treat those two as public. Everything else is server-only. SUPABASE_SERVICE_ROLE_KEY, Stripe secrets and API_KEY_PEPPER must never appear in loader data, client code or logs.

Server and Supabase

VariableRequiredPurposeWhere to get it
NODE_ENVOptionaldevelopment, test or production. Defaults to development. In production the server serves build/client instead of starting Vite.Set production on your host.
HOSTOptionalInterface Express binds to. Defaults to 0.0.0.0.Your platform. Ignored on Vercel, which does not call listen.
PORTOptionalPort Express listens on. Defaults to 3000 in code; the admin example sets 3002. Playwright reads the web value too.Your platform. Pick a different port per worktree when running several servers.
APP_URLRequired in productionPublic HTTP(S) origin of this app. Must have no path, query, hash or credentials. Drives the trusted form-action origin, auth email links and the MCP issuer and resource URLs.Web: http://localhost:3000 locally, your product domain in deployment. Admin: http://localhost:3002 locally, your admin domain in deployment.
WEB_APP_URLAdmin only, required in productionOrigin of the product web app. The admin app uses it to build support sign-in links that land on the web app's /auth/confirm. Same origin rules as APP_URL.http://localhost:3000 locally; the web deployment's APP_URL in production. Not present in apps/web/.env.example.
SUPABASE_URLRequiredSupabase project API URL. Must be set together with SUPABASE_ANON_KEY. Public.env.API_URL from supabase status --output-format json (the example file's placeholder says so), or the project's API settings.
SUPABASE_ANON_KEYRequiredAnonymous key for the request-scoped session client. RLS applies. Public.env.ANON_KEY from the status output, or the project's API settings.
SUPABASE_SERVICE_ROLE_KEYRequired in productionService-role key for the server-only client used after authorization checks, billing webhooks, admin pages and the MCP store. Bypasses RLS.env.SERVICE_ROLE_KEY from the status output, or the project's API settings.

SUPABASE_SERVICE_ROLE_KEY requires SUPABASE_URL. In production, the web app's /health/ready returns 503 until APP_URL, SUPABASE_URL, SUPABASE_ANON_KEY and SUPABASE_SERVICE_ROLE_KEY are all present; the admin app's /health/ready additionally requires WEB_APP_URL.

Optional billing (Stripe)

VariableRequiredPurposeWhere to get it
STRIPE_SECRET_KEYOptionalEnables checkout, customer portal, subscriptions and invoices. Billing shows a disabled state when empty.Stripe dashboard, API keys.
STRIPE_WEBHOOK_SECRETOptionalVerifies events posted to /api/stripe/webhook on the web app.Stripe dashboard, the webhook endpoint's signing secret.
STRIPE_API_URLOptionalOverrides the Stripe API base. Defaults to https://api.stripe.com.Only change it for a proxy or test double.

Set the Stripe values on the admin app too if you use its billing administration pages.

Optional transactional email (Resend)

VariableRequiredPurposeWhere to get it
RESEND_API_KEYOptionalLets sendTransactionalEmail in src/.server/mail.ts deliver app emails. Both this and EMAIL_FROM must be set.Resend dashboard.
RESEND_API_URLOptionalOverrides the Resend API base. Defaults to https://api.resend.com.Only change it for a proxy or test double.
EMAIL_FROMOptionalSender address for app emails.An address on a domain you verified in Resend.
EMAIL_REPLY_TOOptionalReply-to address added to app emails.Your support address.

These variables do not configure Supabase Auth emails (confirmation, magic link, recovery). Those are sent by Supabase using the project's Auth SMTP settings; locally they land in Mailpit. See emails with Resend.

Optional developer API

VariableRequiredPurposeWhere to get it
API_KEY_PEPPEROptionalEnables first-party API keys and /api/v1/me. Ignored unless it has at least 32 characters.Generate a random string of 32 or more characters.
API_CORS_ORIGINOptionalAllowed browser origin for /api/v1/me.The origin of the site that will call the API.

Optional AI (OpenAI-compatible)

VariableRequiredPurposeWhere to get it
OPENAI_API_KEYOptionalEnables /api/ai/chat and /api/ai/image.Your provider's dashboard.
OPENAI_API_URLOptionalAPI base. Defaults to https://api.openai.com.Change it for another OpenAI-compatible provider.
OPENAI_CHAT_MODELOptionalModel used for chat. Chat stays disabled without it.Your provider's model list.
OPENAI_IMAGE_MODELOptionalModel used for image generation. Image generation stays disabled without it.Your provider's model list.

Optional product analytics (PostHog)

VariableRequiredPurposeWhere to get it
ANALYTICS_ENABLEDOptionalCollection runs only when this is exactly true. Defaults to false.Set it yourself. The tracker also respects Do Not Track.
POSTHOG_KEYOptionalPostHog project key, required when analytics is enabled.PostHog project settings.
POSTHOG_HOSTOptionalPostHog host. Defaults to https://us.i.posthog.com.PostHog project settings.

Variables that are not in the example files

VariableRead byPurpose
LOG_LEVELapps/web/server/index.ts, apps/admin/server/index.tspino log level. Defaults to info.
VERCELboth server/index.ts filesSet by Vercel. When present the server exports the Express app instead of calling listen.
ADMIN_BASE_URLapps/web/e2e/seeded-accounts.spec.tsWhere the Playwright suite finds the admin app. Defaults to http://127.0.0.1:3002.
MCP_TEST_SUPABASE_URL, MCP_TEST_SUPABASE_SERVICE_KEY, MCP_TEST_SUPABASE_ANON_KEYapps/web/src/mcp/supabase-store.integration.test.tsPoint the MCP storage integration test at an isolated local Supabase project. The test is skipped when they are missing.
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, TWITTER_API_KEY, TWITTER_API_SECRETapps/database/supabase/config.tomlReferenced as env(...) by the local Supabase Auth provider sections. They configure the local Auth service, not the apps. See authentication.

The repository does not ship an env example for apps/database or apps/email. Local Supabase reads config.toml, and the email preview server needs no configuration.

Installation

Run the TanStack + Supabase starter locally with its own Supabase project, then sign in and create a workspace.

Authentication

How Supabase Auth, cookie sessions, application roles and row-level security protect the TanStack + Supabase starter.

On this page

Public versus server-onlyServer and SupabaseOptional billing (Stripe)Optional transactional email (Resend)Optional developer APIOptional AI (OpenAI-compatible)Optional product analytics (PostHog)Variables that are not in the example files