Environment variables tách config khỏi code — 12-factor app methodology: config là bất kỳ thứ gì thay đổi giữa environments (dev/staging/prod).
- Cấu trúc .env file:
DATABASE_URL=postgresql://...,JWT_SECRET=...,NODE_ENV=development. dotenv:require('dotenv').config()load .env vào process.env, KHÔNG override existing env vars — production inject trực tiếp qua Docker/K8s/CI không cần .env file. dotenv-safe: kiểm tra required vars từ.env.exampletại startup, throw error nếu thiếu thay vì silent undefined. - Config validation với Zod:
const config = z.object({ DATABASE_URL: z.string().url(), PORT: z.coerce.number().default(3000), JWT_SECRET: z.string().min(32) }).parse(process.env)— fail fast với error rõ ràng. - Tạo
config.tsmodule export typed config thay vì accessprocess.envtrực tiếp khắp nơi — dễ test và type-safe. - Lưu ý:
process.env.PORTluôn là string, cần coerce sang number; commit .env vào git — dùng.gitignorevà.env.examplelàm template.
Environment variables separate config from code — 12-factor app methodology: config is anything that changes between environments (dev/staging/prod). .env file structure: DATABASE_URL=postgresql://..., JWT_SECRET=..., NODE_ENV=development. dotenv: require('dotenv').config() loads .env into process.env, does NOT override existing env vars — production injects variables directly via Docker/K8s/CI without needing a .env file. dotenv-safe: validates required vars from .env.example at startup, throws an error if any are missing instead of silently being undefined.
- Config validation with Zod:
const config = z.object({ DATABASE_URL: z.string().url(), PORT: z.coerce.number().default(3000), JWT_SECRET: z.string().min(32) }).parse(process.env)— fail fast with a clear error. - Create a
config.tsmodule that exports typed config instead of accessingprocess.envdirectly throughout the codebase — easier to test and type-safe.
Pitfall: process.env.PORT is always a string, needs coercion to a number; committing .env to git — use .gitignore and .env.example as a template.