process.env.dev

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.

javascript
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:

bash
# 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.js

On Windows, use set in Command Prompt or $env: in PowerShell:

bash
# 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:

javascript
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:

javascript
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:

javascript
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.env are strings. process.env.PORT is "3000", not 3000. Always parse numbers with Number.parseInt() or Number() and compare booleans as strings (=== 'true').
  • Setting process.env.FOO = undefined does not unset the variable — it sets it to the string"undefined". Use delete process.env.FOO instead.
  • In frontend bundlers (Vite, webpack), process.env does not exist at runtime. Bundlers replace process.env.VITE_* or process.env.NEXT_PUBLIC_* at build time. Only prefixed variables are included — others are stripped for security.
  • Avoid reading process.env inside hot loops. While the overhead is small, it involves a syscall each time. Cache values in a configuration object at startup.