Setup Doctor
The setup doctor validates local environment files before runtime failures show up in Next.js or Convex.
The setup doctor validates local environment files before runtime failures show up in Next.js or Convex.
Commands
Run the default check:
bun check-envAlias:
bun setup:doctorThe root build runs the doctor before building:
bun run buildWhat It Reads
The doctor checks the env files for every deployable workspace:
apps/app/.env apps/app/.env.local
packages/backend/.env packages/backend/.env.local
apps/marketing/.env apps/marketing/.env.local
apps/docs/.env apps/docs/.env.localValues in .env.local can override local workspace values.
Shared env contracts live in packages/env, and each deployable re-exports its
own contract from a local env.schema.ts. The apps feed those schemas to t3-env
in src/env.ts at build time, and the doctor imports the package directly to
run the same schemas against the on-disk .env files. Marketing and docs
ship with local URL defaults (marketing on 3002, docs on 3004), so a fresh
clone passes without any of those files.
It also validates setup-config.json when that file is present. The config
must stay valid portable JSON: no comments, no TypeScript build step, and no
package-manager-specific commands other than Bun-compatible commands.
setup-config.json
Edit setup-config.json when you want to change the first-run setup prompts,
default values, or which environment variables the setup flow writes.
Use these sections as the buyer-facing shape:
- Required backend identity values:
APP_NAMEandSITE_URL. - Static browser branding:
packages/config/src/brand.ts. - Deployable destinations: each app's local canonical and cross-app URLs.
- Local development defaults: localhost app and marketing URLs.
- Optional integrations: PostHog, Sentry, and Microsoft auth. Resend is required while password signup, verification, reset, magic-link, and invitation email are enabled.
- Billing providers: Polar, Stripe, or Lemon Squeezy provider IDs.
Prefer environment variables for deployment-specific values. Use
setup-config.json to describe and collect those values; do not put production
secrets directly in the JSON file.
Malformed setup config fails with an error that points at the invalid path,
such as steps[0].variables[1].projects or an unknown project id.
Severity
Errors block the core app from building or booting correctly.
Warnings are optional integrations or provider-specific settings that are not required for the starter to run.
When a billing provider is selected with BILLING_PROVIDER, that provider's
required variables are validated.
Release mode promotes launch-critical optional services, currently product-app Sentry reporting and source-map upload configuration, while leaving disabled billing and analytics integrations as warnings.
Useful Options
Check one workspace:
bun check-env --workspace app
bun check-env --workspace backend
bun check-env --workspace marketing
bun check-env --workspace docsTreat optional warnings as blockers:
bun check-env --strictRun launch release-gate environment validation:
bun check-env --releasePrint machine-readable output:
bun check-env --jsonShow help:
bun check-env --helpSkip the build-time doctor when intentionally building without local env:
SKIP_ENV_DOCTOR=1 bun run buildUse that bypass sparingly. It is useful for constrained CI or documentation checks, but production builds should have real environment configuration.
Common Fixes
Missing Convex URL:
- Fill
NEXT_PUBLIC_CONVEX_URLin the product app env file. - Fill
NEXT_PUBLIC_CONVEX_SITE_URLin the product app env file. - Fill
CONVEX_SITE_URLin the backend env file.
Invalid Better Auth secret:
- Generate a secret with at least 32 non-whitespace characters.
- Set it in
packages/backend/.env. - Set the same value in Convex for backend runtime.
Missing Google OAuth values:
- Configure Google OAuth credentials.
- Set
AUTH_GOOGLE_IDandAUTH_GOOGLE_SECRETin the backend env file. - Set them in Convex for deployed backend runtime.
Billing warnings:
- Leave
BILLING_PROVIDERunset while billing is not in use. - Set
BILLING_PROVIDER=polar,stripe, orlemon_squeezyonly when that provider's variables are ready.
Source
The checker lives in:
tooling/env-doctor/check-env.tsTests live in:
tooling/env-doctor/check-env.test.tsRun the env doctor tests with:
bun test tooling/env-doctor