Finally you can skip dotenv in Node
For years, every Node project started the same way: npm install dotenv, require('dotenv').config() at the top of index.js. Node 20.6 (Sep 2023) finally shipped a built-in alternative — --env-file — and Node 22 (Apr 2024) made it stable. As of 2026, you don't need dotenv for the basic case anymore.
The flag
1node --env-file=.env index.jsVariables in .env show up on process.env. That's it.
The file format is dotenv-style key=value, not INI — there are no [sections], no export FOO=... prefix, and no shell-style ${VAR} expansion of one value referencing another. Quoted multi-line values work but with caveats; if you need anything more sophisticated, stick with dotenv.
DB_URL=postgres://localhost/app
JWT_SECRET=replace-me
LOG_LEVEL=debug
What's new since 20.6
- Node 22 stabilized the flag. No more experimental warnings.
--env-file-if-exists(Node 22+). Same as--env-filebut doesn't error when the file is missing — useful forstartscripts that should run with or without a local.env.process.loadEnvFile([path])(Node 22+). Programmatic API for loading the file from JS code, handy when the path needs to be resolved at runtime. Defaults to.envin the cwd.
1import { loadEnvFile } from 'node:process'
2loadEnvFile() // loads .env from cwd
3loadEnvFile('./config/.env.test')Multiple files and precedence
You can pass --env-file more than once:
1node --env-file=.env --env-file=.env.local index.jsLater files override earlier ones. Variables already set in the actual shell environment beat both — this catches a lot of people. If LOG_LEVEL=info is exported in your shell and LOG_LEVEL=debug is in .env, your app sees info.
NODE_OPTIONS in .env too
Useful trick: set Node CLI flags via NODE_OPTIONS in .env so they're picked up automatically by every node invocation in that directory:
NODE_OPTIONS=--enable-source-maps --inspect
What this isn't
.env files are for local development. They're not a secrets manager. In production, pull values from the orchestrator's secret store (Kubernetes secrets, Vault, AWS Secrets Manager, Railway/Fly/Vercel env vars) instead of shipping .env files.
Bun and Deno
Bun has the same --env-file flag and additionally auto-loads .env from the cwd by default — no flag needed. Deno supports --env-file too. So this isn't a Node-only innovation; it's a runtime-feature-parity moment.
Still need dotenv?
For the simple "load a file at startup" case, no. You still want a library for:
- Variable expansion — values that reference other values. Use
dotenv-expandordotenvx, the modern fork with encryption and multi-environment support. - Encrypted
.envfiles — dotenvx is the way. - Frontend bundles (Vite, Astro, Next, etc.). Those have their own env-loading conventions and don't use the Node runtime in production.