HVRDHVRD
JavaScript

Dotenv

Comprehensive guide to using dotenv for managing environment variables in Node.js applications, covering installation, configuration, security implications, and best practices.

In modern applications, it's critical to separate configuration data from code. This is where environment variables come in — allowing you to store configuration values like database credentials, API keys, and port numbers outside your codebase.

Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env in Node.js applications.


Why Use Dotenv?

  • Keeps sensitive data (e.g., API keys, database URLs) out of source code.
  • Supports multiple environments (development, production, testing).
  • Simplifies configuration management.
  • Works cross-platform without needing system-level configuration.

Installing Dotenv

npm install dotenv

Creating a .env File

The .env file contains key-value pairs representing environment variables.

Example .env file:

PORT=3000
DB_URI=mongodb://localhost:27017/my_database
API_KEY=supersecretapikey

⚠️ Never commit .env to version control. Add .env to your .gitignore file.


Loading Environment Variables

At the very top of your main entry file (e.g., app.js, index.js), require and configure dotenv:

require('dotenv').config();

console.log(process.env.PORT);    // Outputs: 3000
console.log(process.env.DB_URI);  // Outputs: mongodb://localhost:27017/my_database

Or using ES6 import syntax:

import dotenv from 'dotenv';
dotenv.config();

Using Environment Variables

const express = require('express');
const app = express();

const PORT = process.env.PORT || 5000;
const dbUri = process.env.DB_URI;

app.get('/', (req, res) => {
  res.send('Server running!');
});

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

Environment Variable Types

All variables from .env are loaded as strings. If you need to work with numbers or booleans, convert them explicitly:

const PORT = parseInt(process.env.PORT, 10) || 3000;
const IS_PRODUCTION = process.env.NODE_ENV === 'production';

Example: Database Connection Using dotenv

const mongoose = require('mongoose');
require('dotenv').config();

const dbUri = process.env.DB_URI;

mongoose.connect(dbUri, {
  useNewUrlParser: true,
  useUnifiedTopology: true,
})
.then(() => console.log('MongoDB connected'))
.catch(err => console.error('Database connection error:', err));

Advanced Usage

Multiple Environment Files

Use different .env files per environment:

  • .env.development
  • .env.production
  • .env.test

Then load them selectively:

require('dotenv').config({
  path: `.env.${process.env.NODE_ENV}`,
});

Example startup command:

NODE_ENV=development node app.js

Overriding Environment Variables

You can pass variables when starting the process:

PORT=4000 node app.js

Variables passed via the CLI take precedence over .env values.


Security Implications

  • Never commit .env to version control.
  • Keep .env files outside public folders.
  • Use environment-specific files for sensitive credentials.
  • Consider services like Vault or AWS Secrets Manager for production-grade secret management.

Best Practices

  • Use uppercase variable names: API_KEY, DB_URI.
  • Document expected variables in a .env.example file:
PORT=3000
DB_URI=mongodb://localhost:27017/my_database
API_KEY=your_api_key_here
  • Validate that required environment variables are present at runtime.

Example validation:

if (!process.env.DB_URI) {
  throw new Error('Missing DB_URI environment variable');
}