Environment Variables in Node.js
Access env vars with process.env in Node.js and Bun
Reading Environment Variables
In Node.js, environment variables are exposed through the global process.env object. Every property on this object is a string (or undefined if the variable is not set). This is the most fundamental mechanism for configuration in Node.js applications.
const dbUrl = process.env.DATABASE_URL;
const port = Number.parseInt(process.env.PORT ?? '3000', 10);
const isProduction = process.env.NODE_ENV === 'production';Bun also supports process.env with the same API. Additionally, Bun reads .envfiles automatically without needing a dotenv library, making it even more convenient for local development.
Setting Environment Variables
Set environment variables before starting the process. On Linux and macOS, prefix them directly in the command line or export them in your shell:
# Inline for a single command
DATABASE_URL=postgres://localhost/mydb node server.js
# Export for the current shell session
export DATABASE_URL=postgres://localhost/mydb
node server.jsOn Windows, use set in Command Prompt or $env: in PowerShell:
# Command Prompt
set DATABASE_URL=postgres://localhost/mydb
# PowerShell
$env:DATABASE_URL = "postgres://localhost/mydb"You can also set environment variables programmatically within Node.js, though this only affects the current process and its children:
process.env.MY_VAR = 'some-value';Popular Libraries
dotenv is the most widely used library for loading .env files in Node.js. Call dotenv.config() at the very beginning of your entry file, before importing any modules that depend on environment variables:
import 'dotenv/config';
// or
import dotenv from 'dotenv';
dotenv.config();envalid provides validation and type coercion. It ensures that required variables are present and correctly formatted at startup:
import { cleanEnv, str, port, bool } from 'envalid';
const env = cleanEnv(process.env, {
DATABASE_URL: str(),
PORT: port({ default: 3000 }),
DEBUG: bool({ default: false }),
});
// env.DATABASE_URL is a string (guaranteed to exist)
// env.PORT is a number
// env.DEBUG is a boolean@t3-oss/env-core integrates with TypeScript and Zod to provide fully typed, validated environment configuration with excellent DX in frameworks like Next.js and tRPC.
Common Gotchas
- All values in
process.envare strings.process.env.PORTis"3000", not3000. Always parse numbers withNumber.parseInt()orNumber()and compare booleans as strings (=== 'true'). - Setting
process.env.FOO = undefineddoes not unset the variable — it sets it to the string"undefined". Usedelete process.env.FOOinstead. - In frontend bundlers (Vite, webpack),
process.envdoes not exist at runtime. Bundlers replaceprocess.env.VITE_*orprocess.env.NEXT_PUBLIC_*at build time. Only prefixed variables are included — others are stripped for security. - Avoid reading
process.envinside hot loops. While the overhead is small, it involves a syscall each time. Cache values in a configuration object at startup.