Configuration & Environment Variables
Relevant source files
The following files were used as context for generating this wiki page:
This project utilizes a structured approach to manage environment variables across its different applications (api, web) and shared packages (db). Configuration is handled through .env files at the monorepo root, and type-safe access is enforced using the @t3-oss/env-core library with zod for validation. This ensures that applications and packages only start if their required environment variables are present and correctly formatted.
The core strategy involves a central .env file, created from .env.example, which contains all necessary variables for the different parts of the monorepo. The dotenv-cli package is used within pnpm scripts to load these variables into the environment for specific commands, particularly for the backend API and database tooling.
Core Strategy
.env File Management
A single .env file at the root of the monorepo is the source of truth for all environment-specific configurations. A template file, .env.example, is provided to guide developers on the required variables.
To set up the local environment, developers must copy the example file and populate it with the correct values.
cp .env.example .env
# Edit .env with your database connection string and other settings
Sources: README.md:60-62
Loading Variables with dotenv-cli
For server-side applications and scripts, dotenv-cli is used to load variables from the root .env file. This is implemented via a reusable pnpm script named with-env in the api and db packages.
This script is then prepended to other commands like dev, push, or studio to ensure the environment is correctly configured before execution.
Example from apps/api/package.json:
"scripts": {
"dev": "pnpm with-env tsx watch src/index.ts",
"with-env": "dotenv -e ../../.env --"
}
Example from packages/db/package.json:
"scripts": {
"push": "pnpm with-env drizzle-kit push",
"studio": "pnpm with-env drizzle-kit studio",
"with-env": "dotenv -e ../../.env --"
}
Sources: apps/api/package.json:5-6, packages/db/package.json:14-16
Type-Safe Validation with T3 Env
To prevent runtime errors due to missing or invalid environment variables, the project uses @t3-oss/env-core. Each application (api, web) and the db package has its own env.ts file that defines, validates, and exports its required variables. This library uses zod to define schemas for the variables, ensuring they conform to expected types (e.g., string, url).
The createEnv function is configured with:
serverorclientobjects defining the variable schemas.runtimeEnvspecifying the source object (process.envfor server,import.meta.envfor client).emptyStringAsUndefined: trueto correctly handle empty strings in.envfiles.
Sources: apps/api/src/env.ts, apps/web/src/env.ts, packages/db/env.ts
Application-Specific Configurations
API Server (apps/api)
The API server requires configuration for its authentication service. These are defined as server-side variables.
The diagram below illustrates how API environment variables are loaded and validated.
| Variable | Scope | Zod Type | Description |
|---|---|---|---|
BETTER_AUTH_URL | Server | z.string().url() | The URL of the Better Auth service. |
BETTER_AUTH_SECRET | Server | z.string() | The secret key for the Better Auth service. |
Sources: .env.example:3-4, apps/api/src/env.ts:9-10
Web Frontend (apps/web)
The web application distinguishes between server-side and client-side environment variables. Client-side variables must be prefixed with VITE_ to be exposed to the browser.
- Server-side:
SERVER_URLis available only during server-side rendering or build processes. - Client-side:
VITE_APP_TITLEis available in the browser.
The runtimeEnv for the web app is import.meta.env, which is populated by Vite.
The following diagram shows the validation flow for both client and server variables in the web app.
Sources: apps/web/src/env.ts:4-29
| Variable | Scope | Zod Type | Description |
|---|---|---|---|
SERVER_URL | Server | z.string().url().optional() | The base URL of the API server. Optional. |
VITE_APP_TITLE | Client | z.string().min(1).optional() | The title of the web application. Optional. |
Sources: .env.example:6-7, apps/web/src/env.ts:5-15
Database Package (packages/db)
The db package requires a single environment variable to connect to the PostgreSQL database. This is used by Drizzle ORM and Drizzle Kit scripts.
This diagram shows the database connection string being loaded for Drizzle Kit commands.
| Variable | Scope | Zod Type | Description |
|---|---|---|---|
DATABASE_URL | Server | z.string().url() | The connection URL for PostgreSQL. |
Sources: .env.example:1, packages/db/env.ts:9
Summary
The configuration management in this monorepo is designed for robustness and developer ergonomics. By centralizing variables in a root .env file, using dotenv-cli for server-side loading, and enforcing type-safety with @t3-oss/env-core in each package, the project minimizes configuration-related errors. This separation of concerns ensures that each part of the application only has access to the environment variables it needs, following the principle of least privilege.