Environment Variables Philosophy
How environment variables are managed and validated.
Core Principles
- Type Safety with Zod: We use
zod
to define schemas for our environment variables (src/env/schemas
). This provides compile-time and runtime validation, preventing errors caused by missing or incorrectly typed variables. - Clear Separation: Environment variables are strictly separated into:
- Client-side: Variables prefixed with
NEXT_PUBLIC_
are accessible in the browser. These are defined and validated insrc/env/client.ts
. - Server-side: Variables used exclusively on the server (e.g., API keys, database URLs) are handled in
src/env/index.ts
.
- Client-side: Variables prefixed with
- Validation on Build/Start: The application validates all required environment variables when it builds or starts. If any variables are missing or invalid according to the Zod schemas, the process will fail with a descriptive error message, preventing runtime issues.
- Modular Schemas: Server-side schemas are further broken down by feature (e.g.,
email
,auth
) insrc/env/schemas/
and then merged. This keeps the configuration organized and easier to manage as the application grows. - Single Source of Truth: The validated and processed environment variables are exported from
src/env/index.ts
(serverEnv
) andsrc/env/client.ts
(clientEnv
), serving as the single source of truth throughout the application.
Application URL Configuration
The application needs to know its public-facing URL for various features like authentication callbacks and generating absolute links. The deployment URL is typically derived automatically based on environment variables provided by platforms like Vercel, Railway, Render, and Coolify.
This derived URL is configured in next.config.js
and passed to the application via the NEXT_PUBLIC_APP_URL
environment variable.
Overriding the URL:
If the automatically derived URL is incorrect, or if you need to specify a different primary URL, you can manually set the SERVER_URL
environment variable. This value will take precedence.
Handling Multiple Domains
If your deployment platform supports multiple domains for a single deployment, be aware that relying on the automatically derived URL might lead to issues. The platform might provide a list of domains, causing problems for features expecting a single canonical URL (like authentication). The recommended approach is to create a separate deployment for each domain you want to serve. Each deployment should then have the SERVER_URL
environment variable explicitly set to its corresponding domain.
Refer to .env.example
for a list of all required environment variables and their intended purpose. The specific schemas in src/env/schemas/
define the expected types and validations.
Generating .env
To help generate your initial .env
file based on these schemas, you can use the online tool zts-env.vercel.app.
Debugging Pages
For debugging purposes during development, there are two pages available to view environment variables:
- /env: (
src/app/env-client/page.tsx
) This page is publicly accessible and displays only the client-sideNEXT_PUBLIC_
variables that have been explicitly exposed viaclientEnv
. - /env-server: (
src/app/env-server/page.tsx
) This page displays a curated list of server-side environment variables (primarily related to deployment environments like Vercel, Railway, Coolify). Access to this page is restricted to administrators via theadminProcedure
in the tRPC router (src/server/api/routers/admin.ts
).
Important: If you prefer not to expose any environment variables through the UI, even for admins, feel free to delete the src/app/env-client/
and src/app/env-server/
directories, as well as the corresponding adminRouter
(getEnvVars
procedure) in src/server/api/routers/admin.ts
.