How to Set Up a Dotenv File in Node.js Using the dotenv NPM Package

To set up a dotenv file in Node.js, install the dotenv package via npm, create a .env file with KEY=VALUE pairs, and call require('dotenv').config() at the top of your entry file to load the variables into process.env.

Node.js applications frequently require sensitive configuration data—such as database URLs and API keys—that should never be hard-coded. The dotenv npm package provides a robust solution for managing these secrets by loading them from a local .env file into process.env at runtime. While the Node.js runtime itself includes a minimal built-in parser for environment files (implemented in src/node_dotenv.h and src/node_dotenv.cc within the nodejs/node repository), the dotenv package offers greater flexibility and explicit control from your JavaScript code.

How the dotenv Package Works

When you invoke require('dotenv').config(), the package reads your .env file line-by-line, parses each KEY=VALUE pair, and injects them into the process.env object exposed by Node.js core (defined in src/node_process_methods.cc). This happens synchronously before your application logic executes, ensuring that environment variables are available immediately. Values are always stored as strings, so you must manually convert them to numbers or booleans when needed.

Step-by-Step Guide to Setting Up dotenv in Node.js

Install the dotenv NPM Package

Add the package to your project dependencies using your preferred package manager:

npm install dotenv --save

Create the .env File

At the root of your project, create a file named .env. Each line should follow the KEY=VALUE syntax. Lines beginning with # are treated as comments.


# Database configuration

DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp

# API credentials

API_KEY=super-secret-token

Load Environment Variables in Your Application

Import and configure dotenv at the very top of your entry file (e.g., index.js or app.js) to ensure variables are loaded before any other modules execute:

// index.js
require('dotenv').config();

// Application code starts here
console.log('Database host:', process.env.DB_HOST);

Access Variables via process.env

Retrieve values anywhere in your codebase using process.env.KEY. Remember to handle type conversion since all values are strings:

const dbHost = process.env.DB_HOST;
const dbPort = Number(process.env.DB_PORT);
const apiKey = process.env.API_KEY;

Advanced Configuration Options

Load Custom File Paths

For projects with multiple environments (development, testing, production), specify a custom path using the path option:

require('dotenv').config({ path: './config/production.env' });

Handle Loading Errors

The config() method returns an object containing an error property if the file cannot be read. Implement error handling to fail fast during startup:

const result = require('dotenv').config({ path: './config/.env' });

if (result.error) {
  console.error('Failed to load environment variables:', result.error);
  process.exit(1);
}

Type Conversion and Validation

Create helper functions to safely convert environment strings to typed values:

require('dotenv').config();

function asNumber(key, fallback) {
  const value = process.env[key];
  return value !== undefined ? Number(value) : fallback;
}

const maxConnections = asNumber('MAX_CONN', 10);
const debugMode = process.env.DEBUG === 'true';

Security Best Practices for dotenv Files

Never commit your .env file to version control. Add it to your .gitignore file immediately. The Node.js repository itself follows this pattern, as seen in deps/undici/src/.gitignore.


# .gitignore

.env
.env.local
.env.*.local

Provide a .env.example file in your repository that documents the required keys without exposing actual secrets:


# .env.example

DB_HOST=
DB_PORT=
API_KEY=

Summary

  • Install the dotenv package via npm install dotenv to manage environment-specific configuration.
  • Create a .env file at your project root using KEY=VALUE syntax, keeping it out of version control as specified in the Node.js source patterns.
  • Load variables early by calling require('dotenv').config() at the top of your entry file, which populates process.env using the same parsing concepts found in Node.js core files like src/node_dotenv.cc.
  • Access values anywhere via process.env, converting strings to numbers or booleans as needed, and use the path option to support multiple environments.

Frequently Asked Questions

What is the difference between the dotenv package and Node.js built-in --env-file flag?

The dotenv npm package provides programmatic control from JavaScript, allowing you to load custom files, handle errors gracefully, and execute logic before your app starts. Node.js also ships with a native .env parser (implemented in src/node_dotenv.h and src/node_dotenv.cc) that activates when using the --env-file CLI flag. The native approach requires no dependencies but offers less flexibility for dynamic file selection within your code.

Can I use multiple .env files for different environments?

Yes. Instead of relying on a single .env file, pass the path option to config() to load environment-specific files such as .env.development or .env.production. Call this early in your application bootstrap to ensure the correct variables are available before other modules execute.

Why are my environment variables undefined after calling config()?

This typically occurs when the .env file is missing, the path option points to the wrong location, or the file contains syntax errors. The config() method returns an object with an error property if loading fails. Always check this property or verify the file exists at the expected path relative to your working directory.

Should I commit my .env file to version control?

No. The .env file should never be committed to Git or any version control system, as it typically contains sensitive credentials. Add .env to your .gitignore file immediately. The Node.js repository follows this security practice in paths like deps/undici/src/.gitignore. Instead, commit a .env.example file that lists the required keys without values to document the configuration schema for other developers.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s https://instagit.com/install.md

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client