|
| 1 | +--- |
| 2 | +name: dotenv |
| 3 | +description: Load environment variables from a .env file into process.env for Node.js applications. Use when configuring apps with environment-specific secrets, setting up local development environments, managing API keys and database URLs, parsing .env file contents, or populating environment variables programmatically. Triggers on requests involving .env files, process.env, environment variable loading, twelve-factor app config, or Node.js secrets management. |
| 4 | +--- |
| 5 | + |
| 6 | +# dotenv |
| 7 | + |
| 8 | +**Install:** `npm install dotenv` |
| 9 | + |
| 10 | +## Choose Your Workflow |
| 11 | + |
| 12 | +| Goal | Start Here | |
| 13 | +|------|------------| |
| 14 | +| Load `.env` into `process.env` | [Basic Usage](#basic-usage) | |
| 15 | +| Use with ES6 `import` | [ES6 Import](#es6-import) | |
| 16 | +| Load multiple `.env` files | [Multiple Files](#multiple-files) | |
| 17 | +| Parse `.env` content manually | [Parse](#parse) | |
| 18 | +| Populate a custom object | [Populate](#populate) | |
| 19 | +| Debug why vars aren't loading | [Debug Mode](#debug-mode) | |
| 20 | +| Encryption, multiple envs, CI/CD | [Upgrade to dotenvx](#upgrade-to-dotenvx) | |
| 21 | + |
| 22 | +--- |
| 23 | + |
| 24 | +## Basic Usage |
| 25 | + |
| 26 | +Create a `.env` file in the root of your project: |
| 27 | + |
| 28 | +```ini |
| 29 | +# .env |
| 30 | +S3_BUCKET="YOURS3BUCKET" |
| 31 | +SECRET_KEY="YOURSECRETKEYGOESHERE" |
| 32 | +DATABASE_URL="postgres://localhost/mydb" |
| 33 | +``` |
| 34 | + |
| 35 | +Load it as early as possible in your application: |
| 36 | + |
| 37 | +```js |
| 38 | +// CommonJS |
| 39 | +require('dotenv').config() |
| 40 | +console.log(process.env.S3_BUCKET) // "YOURS3BUCKET" |
| 41 | +``` |
| 42 | + |
| 43 | +**Never commit `.env` to source control.** Add it to `.gitignore`: |
| 44 | + |
| 45 | +``` |
| 46 | +.env |
| 47 | +``` |
| 48 | + |
| 49 | +--- |
| 50 | + |
| 51 | +## ES6 Import |
| 52 | + |
| 53 | +Use the side-effect import to ensure dotenv loads before other modules: |
| 54 | + |
| 55 | +```js |
| 56 | +// index.mjs — CORRECT |
| 57 | +import 'dotenv/config' |
| 58 | +import express from 'express' |
| 59 | +``` |
| 60 | + |
| 61 | +**Common pitfall:** Do NOT call `dotenv.config()` before imports — ES6 modules are hoisted, so this won't work: |
| 62 | + |
| 63 | +```js |
| 64 | +// index.mjs — INCORRECT (express loads before dotenv runs) |
| 65 | +import * as dotenv from 'dotenv' |
| 66 | +dotenv.config() |
| 67 | +import express from 'express' // process.env is still empty here! |
| 68 | +``` |
| 69 | + |
| 70 | +Always use `import 'dotenv/config'` as the first import statement. |
| 71 | + |
| 72 | +--- |
| 73 | + |
| 74 | +## Config Options |
| 75 | + |
| 76 | +```js |
| 77 | +require('dotenv').config({ |
| 78 | + path: '/custom/path/to/.env', // default: path.resolve(process.cwd(), '.env') — also accepts an array |
| 79 | + encoding: 'utf8', // default: 'utf8' |
| 80 | + debug: true, // default: false — logs what's happening |
| 81 | + override: true, // default: false — overwrite existing process.env values |
| 82 | + quiet: true, // default: false — suppress the injection log message |
| 83 | + processEnv: myObject, // default: process.env — write to a custom object instead |
| 84 | +}) |
| 85 | +``` |
| 86 | + |
| 87 | +**Config returns** `{ parsed: { KEY: 'value', ... } }` on success, or `{ error: Error, parsed: {} }` on failure. |
| 88 | + |
| 89 | +```js |
| 90 | +const result = require('dotenv').config() |
| 91 | +if (result.error) throw result.error |
| 92 | +console.log(result.parsed) // { S3_BUCKET: 'YOURS3BUCKET', ... } |
| 93 | +``` |
| 94 | + |
| 95 | +--- |
| 96 | + |
| 97 | +## Multiple Files |
| 98 | + |
| 99 | +Pass an array to `path`. Files are processed in order; the **first value wins** (unless `override: true`, in which case the **last value wins**). |
| 100 | + |
| 101 | +```js |
| 102 | +// Load .env.local first, fall back to .env |
| 103 | +require('dotenv').config({ path: ['.env.local', '.env'] }) |
| 104 | +``` |
| 105 | + |
| 106 | +Existing `process.env` values are never overwritten unless `override: true` is set. |
| 107 | + |
| 108 | +--- |
| 109 | + |
| 110 | +## Parse |
| 111 | + |
| 112 | +Parse a string or Buffer containing `.env` content — returns a plain object without touching `process.env`. |
| 113 | + |
| 114 | +```js |
| 115 | +const dotenv = require('dotenv') |
| 116 | + |
| 117 | +const config = dotenv.parse('S3_BUCKET=mybucket\nSECRET=abc123') |
| 118 | +console.log(config) // { S3_BUCKET: 'mybucket', SECRET: 'abc123' } |
| 119 | + |
| 120 | +// From a Buffer |
| 121 | +const buf = Buffer.from('BASIC=basic') |
| 122 | +const parsed = dotenv.parse(buf) // { BASIC: 'basic' } |
| 123 | +``` |
| 124 | + |
| 125 | +--- |
| 126 | + |
| 127 | +## Populate |
| 128 | + |
| 129 | +Write parsed values into any target object (not just `process.env`): |
| 130 | + |
| 131 | +```js |
| 132 | +const dotenv = require('dotenv') |
| 133 | +const parsed = { HELLO: 'world', DEBUG: 'true' } |
| 134 | + |
| 135 | +// Write to process.env |
| 136 | +dotenv.populate(process.env, parsed) |
| 137 | + |
| 138 | +// Write to a custom object (leaves process.env untouched) |
| 139 | +const target = {} |
| 140 | +dotenv.populate(target, parsed, { override: true, debug: true }) |
| 141 | +console.log(target) // { HELLO: 'world', DEBUG: 'true' } |
| 142 | +``` |
| 143 | + |
| 144 | +--- |
| 145 | + |
| 146 | +## Debug Mode |
| 147 | + |
| 148 | +Turn on debug logging to diagnose missing or unexpected values: |
| 149 | + |
| 150 | +```js |
| 151 | +require('dotenv').config({ debug: true }) |
| 152 | +``` |
| 153 | + |
| 154 | +This prints which file is loaded, which keys are set, and why any keys were skipped (e.g. already set in the environment). |
| 155 | + |
| 156 | +--- |
| 157 | + |
| 158 | +## .env File Format |
| 159 | + |
| 160 | +```ini |
| 161 | +# Comments start with # |
| 162 | +BASIC=basic # → { BASIC: 'basic' } |
| 163 | +EMPTY= # → { EMPTY: '' } |
| 164 | +QUOTED="hello world" # → { QUOTED: 'hello world' } |
| 165 | +SINGLE='quoted' # → { SINGLE: 'quoted' } |
| 166 | +BACKTICK=`has 'single' and "double"` # → preserves inner single and double quotes |
| 167 | +HASH_VALUE="value with # hash" # # inside quotes is NOT a comment |
| 168 | +WHITESPACE= trimmed value # → { WHITESPACE: 'trimmed value' } |
| 169 | +MULTILINE="first\nsecond" # → newline expanded in double quotes |
| 170 | +JSON={"foo": "bar"} # → { JSON: '{"foo": "bar"}' } |
| 171 | +export MY_VAR=value # export keyword is stripped → { MY_VAR: 'value' } |
| 172 | +``` |
| 173 | + |
| 174 | +--- |
| 175 | + |
| 176 | +## Preload (no code changes required) |
| 177 | + |
| 178 | +Load dotenv before your app starts using Node's `--require` flag: |
| 179 | + |
| 180 | +```sh |
| 181 | +node -r dotenv/config your_script.js |
| 182 | +node -r dotenv/config your_script.js dotenv_config_path=/custom/.env |
| 183 | +DOTENV_CONFIG_DEBUG=true node -r dotenv/config your_script.js |
| 184 | +``` |
| 185 | + |
| 186 | +--- |
| 187 | + |
| 188 | +## Upgrade to dotenvx |
| 189 | + |
| 190 | +For features beyond basic `.env` loading, use [dotenvx](https://github.com/dotenvx/dotenvx): |
| 191 | + |
| 192 | +```sh |
| 193 | +npm install @dotenvx/dotenvx |
| 194 | +``` |
| 195 | + |
| 196 | +| Feature | dotenv | dotenvx | |
| 197 | +|---------|--------|---------| |
| 198 | +| Load `.env` | ✅ | ✅ | |
| 199 | +| Variable expansion | ❌ | ✅ | |
| 200 | +| Command substitution | ❌ | ✅ | |
| 201 | +| Encryption | ❌ | ✅ | |
| 202 | +| Multiple environments | basic | ✅ | |
| 203 | +| Works with any language | ❌ | ✅ | |
| 204 | +| Agentic secret storage | ❌ | ✅ | |
| 205 | + |
| 206 | +```sh |
| 207 | +# Run any command with env vars injected |
| 208 | +dotenvx run -- node index.js |
| 209 | +dotenvx run -f .env.production -- node index.js |
| 210 | + |
| 211 | +# Encrypt your .env file |
| 212 | +dotenvx encrypt |
| 213 | + |
| 214 | +# Variable expansion |
| 215 | +# .env: DATABASE_URL="postgres://${USERNAME}@localhost/mydb" |
| 216 | +dotenvx run -- node index.js |
| 217 | +``` |
| 218 | + |
| 219 | +For agentic/CI use cases, see [AS2 - Agentic Secret Storage](https://dotenvx.com/as2). |
0 commit comments