Root env files, Vercel env management, Supabase values, Stripe values, and Turbo task env forwarding.
Apps load environment variables from the repository root. Deployed services share one Vercel project environment. Next.js apps call loadMonorepoEnv (via @workspace/next-config) so they read the root files even though each app lives under apps/<name>.
| File | Purpose |
|---|---|
.env.example | Tracked template (no secrets) |
.env.local | From pnpm env:pull:development (gitignored) |
.env.development.local | Local overrides that survive pulls (Portless URLs, local Supabase, DEV_LOGIN_*) |
.env.production.local | From pnpm env:pull:production for local production builds |
supabase/.env.example → supabase/.env.local | Supabase CLI Google OAuth (GOOGLE_OAUTH_CLIENT_ID / _SECRET) and CLI-only settings |
Copy .env.example to .env.local when you are not linked to Vercel yet, then fill required values. Prefer pnpm env:pull (development + production) when the root project is linked.
For local Supabase, pnpm supabase:start writes NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY, SUPABASE_SECRET_KEY, POSTGRES_URL, SMTP_HOST and SMTP_PORT into .env.development.local from supabase status. Ports differ per git worktree and branch, so do not copy them by hand. Other common values are:
# Optional. Leave it unset or set it to https://localhost so the default brand
# resolves to https://app.localhost.
# NEXT_PUBLIC_SITE_URL=https://localhostLink the repository root to the CentraKit Vercel project and manage deployed values there (including marketplace integrations for Sentry, Supabase, Stripe, and Resend).
pnpm env:pull # development → .env.local + production → .env.production.local
pnpm env:pull:development
pnpm env:pull:production
pnpm env:pull:preview # → .env.preview.local (optional; Next does not auto-load it)Prefer shared integration names (NEXT_PUBLIC_SENTRY_DSN / SENTRY_*, Supabase, Stripe, Resend). AI Gateway and Vercel Connect use VERCEL_OIDC_TOKEN from pnpm env:pull. Sentry SDK initialization is disabled in local development.
Keep local-only overrides in .env.development.local so development pulls into .env.local do not wipe Portless or local Supabase settings.
Turborepo only forwards variables listed in a task's env array or global env configuration. If a build needs a secret or public value, add it to that app's turbo.json task configuration, root globalEnv, or globalPassThroughEnv.
NEXT_PUBLIC_SITE_URL is in root globalEnv so CI and local next build hash it. SENTRY_AUTH_TOKEN is in build passThroughEnv so the Sentry plugin can see it without affecting the cache hash.
Public URLs come from the brand registry in packages/foundation/src/brands.ts, not from env. Each brand has one app host per environment, and the API, MCP server and docs are the /api, /mcp and /docs paths on it. brandUrls(brand) returns those URLs.
| Variable | Effect |
|---|---|
VERCEL_ENV | Picks the host set: production uses the production hosts, preview and development use the *.centrakit.dev hosts, and anything else, including unset, uses the local *.localhost hosts. Client bundles read NEXT_PUBLIC_VERCEL_ENV, which Vercel sets to the same value. |
NEXT_PUBLIC_SITE_URL | Only overrides the default brand's origin in the local environment, for example http://localhost:3100 in E2E builds. https://localhost or an unset value keeps https://app.localhost. Deployed environments ignore it. |
LOCAL_API_ORIGIN | Off Vercel only. The API server that the SaaS /api, /mcp and /.well-known/oauth-protected-resource rewrites target, for example http://127.0.0.1:3101 in E2E builds. Unset uses https://api.localhost. |
MCP_RESOURCE_AUDIENCE | An extra accepted token audience for the MCP server, next to the /mcp URL of every brand host and Supabase's default authenticated audience. Set it to https://api.centrakit.com/api/mcp while MCP clients move off the old host. |
See Brand hosts and rollout for the host list.
Do not commit .env.local files or credentials. Document variable names and ownership, not real secret values.
Last updated on