Two ways env is read

There are two patterns in the repo and you need to know which one a file uses. The ESLint rule perform-internal/no-direct-process-env blocks process.env everywhere except packages/config and the ported @repo/* directories, which are exempted in eslint.config.mjs. apps/mcp-server disables the rule in its one file because it runs on a coach’s machine with two variables.

defineEnv

@perform/config exports one function:
It loads .env once with dotenv, runs schema.safeParse(process.env), and on failure writes one line per issue to stderr and calls process.exit(78). apps/core-api/src/config.ts wraps it:
load-env.ts calls loadEnv() as a side effect so the first import in server.ts validates the environment before any other module is evaluated. Booleans are strings in env. The schema converts them with value === 'true' || value === '1'.

Core API schema

Every variable below is in apps/core-api/src/config.ts. “Required” means the schema has no default.

Server and infrastructure

Rate limits

Auth

SmartSend and trainee login

config.ts ships real default values for TRAINEE_REVIEW_PHONE, TRAINEE_REVIEW_CODE and WAITLIST_WEBHOOK_URL. A deployment that does not override them inherits a working login bypass for that phone number. Override or blank them per environment.

AI

See AI features.

Storage

AutoFit import

Variables read by @repo packages

These are not in the Zod schema. They are read with process.env inside the package that needs them.

Adding a variable

1

Add it to the schema

Add the key to the z.object in apps/core-api/src/config.ts. Give optional values a default so local development still boots.
2

Read it from the context

Use ctx.env.MY_VALUE in the router factory and pass it into the service as config. Do not pass the whole env into a service.
3

Document it

Add it to this page. The older backend notes refer to a tracked .env.example, but the working tree has no such file, only local .env files at the repo root, apps/core-api, packages/db and packages/database. This page is the current list of variable names.