dotenv-flow: Environment Variable Management
dotenv-flow is an extension of the popular `dotenv` package, designed to simplify environment variable management across multiple deployment environments in Node.js applications. It introduces robust support for `NODE_ENV`-specific `.env` files (e.g., `.env.development`, `.env.production`, `.env.test`) and `.local` overrides (e.g., `.env.development.local`) to manage environment variables dynamically based on the current `NODE_ENV`. The package automatically loads the appropriate `.env` files in a predefined order, allowing variables in more specific files to override those in more general ones. This structured approach is inspired by Ruby's `dotenv-rails` and CreateReactApp's configuration patterns, adhering closely to the Twelve-Factor App methodology's principles for storing configuration in the environment. The current stable version is 4.1.0, with an active release cadence that regularly introduces new features and bug fixes, such as customizable file patterns in v4.0.0 and explicit file lists in v4.1.0, enhancing its flexibility and control over environment loading.
Common errors
-
Error loading .env files: Error: ENOENT: no such file or directory, open '<path-to-file>'
cause dotenv-flow could not find the expected .env files at the specified path or in the current working directory.fixEnsure your `.env` files are in the project root or provide the correct `path` option to `dotenvFlow.config({ path: '/absolute/path/to/project/root' })`. -
ReferenceError: require is not defined in ES module scope
cause Attempting to use CommonJS `require()` syntax within an ES Module (ESM) file.fixFor ESM, use `import dotenvFlow from 'dotenv-flow';` for programmatic use or `import 'dotenv-flow/config';` for preloading. -
TypeError: dotenvFlow.config is not a function
cause Incorrect import syntax for ESM, trying to destructure `config` from the default export.fixUse `import dotenvFlow from 'dotenv-flow';` and then call `dotenvFlow.config();`. The `config` function is a method of the default `dotenvFlow` object, not a named export. -
My environment variables are not loading or have incorrect values.
cause This often stems from an incorrect `NODE_ENV` setting, misunderstanding the file loading precedence, or the files themselves being malformed.fixVerify that `process.env.NODE_ENV` is correctly set for your desired environment. Check the order of your `.env` files for unintended overrides. Use `dotenvFlow.config({ debug: true })` (since v4.0.0) to output detailed loading information.
Warnings
- gotcha Files like `.env.local` and `.env.<NODE_ENV>.local` contain local-specific overrides and sensitive information. These should always be added to your `.gitignore` file to prevent accidental commitment to version control.
- gotcha dotenv-flow loads environment variables based on a specific precedence: `.env` < `.env.<NODE_ENV>` < `.env.local` < `.env.<NODE_ENV>.local`. Variables defined in later files will override those defined in earlier ones. Misunderstanding this order can lead to unexpected variable values.
- gotcha The behavior of dotenv-flow is heavily reliant on the `NODE_ENV` environment variable. If `NODE_ENV` is not set, dotenv-flow defaults to `development` which might not be the intended behavior in production or test environments.
- gotcha When using the programmatic `config()` method, ensure it is called as early as possible in your application's entry point to guarantee that environment variables are available throughout your codebase. Calling it too late may result in modules attempting to access `process.env` before it's populated.
Install
-
npm install dotenv-flow -
yarn add dotenv-flow -
pnpm add dotenv-flow
Imports
- dotenvFlow
import { config } from 'dotenv-flow';import dotenvFlow from 'dotenv-flow';
- config() (programmatic CJS)
import dotenvFlow from 'dotenv-flow'; dotenvFlow.config(); // This is ESM; using require() in ESM context is a syntax error
require('dotenv-flow').config(); - config (preload CJS)
import 'dotenv-flow/config';
require('dotenv-flow/config');
Quickstart
// For this example, assume you have these files in your project root:
// .env
// APP_NAME=MyUniversalApp
// GLOBAL_SETTING=true
// .env.development
// NODE_ENV=development
// API_URL=http://localhost:3000
// .env.development.local
// DB_USER=dev_local
// DEBUG_MODE=true
import dotenvFlow from 'dotenv-flow';
// It's good practice to explicitly set NODE_ENV for predictable behavior,
// though dotenv-flow also checks process.env.NODE_ENV.
// For demonstration purposes, we can override it here.
// In a real application, NODE_ENV would usually be set by the host environment.
// For example: `NODE_ENV=development node app.js` or `NODE_ENV=production node app.js`
// Simulate running in development for local testing
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
// Load environment variables based on the current NODE_ENV
const result = dotenvFlow.config();
if (result.error) {
console.error('Failed to load environment variables:', result.error);
} else {
console.log(`Environment loaded for NODE_ENV: ${process.env.NODE_ENV}`);
console.log('--- Loaded Variables ---');
console.log('APP_NAME:', process.env.APP_NAME); // From .env
console.log('GLOBAL_SETTING:', process.env.GLOBAL_SETTING); // From .env
console.log('API_URL:', process.env.API_URL); // From .env.development
console.log('DB_USER:', process.env.DB_USER); // From .env.development.local
console.log('DEBUG_MODE:', process.env.DEBUG_MODE); // From .env.development.local
console.log('------------------------');
// Example of using a loaded variable
if (process.env.DEBUG_MODE === 'true') {
console.log('Debug mode is ENABLED. Happy coding!');
}
}