dotenv Complete Guide | Environment Variables in Node.js
이 글의 핵심
dotenv loads environment variables from a .env file into process.env. It's the standard way to manage configuration and secrets in Node.js applications.
Introduction
dotenv is a zero-dependency module that loads environment variables from a .env file into process.env. It’s the standard for managing configuration in Node.js apps.
The Problem
Hardcoded values (bad):
const db = mysql.createConnection({
host: 'localhost',
user: 'admin',
password: 'secret123', // ❌ Exposed in code!
database: 'myapp',
});
With dotenv (good):
require('dotenv').config();
const db = mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD, // ✅ Secret not in code
database: process.env.DB_NAME,
});
1. Installation
npm install dotenv
2. Basic Usage
Create .env file:
# .env
DB_HOST=localhost
DB_USER=admin
DB_PASSWORD=secret123
DB_NAME=myapp
PORT=3000
Load in your app:
// Load as early as possible
require('dotenv').config();
// Now use environment variables
console.log(process.env.DB_HOST); // 'localhost'
console.log(process.env.PORT); // '3000'
3. ES Modules
import 'dotenv/config';
// Or
import dotenv from 'dotenv';
dotenv.config();
console.log(process.env.DB_HOST);
4. Custom Path
require('dotenv').config({ path: '/custom/path/.env' });
// Or multiple files
require('dotenv').config({ path: '.env.local' });
require('dotenv').config({ path: '.env' });
5. Multi-Environment Setup
Development
# .env.development
NODE_ENV=development
DB_HOST=localhost
DB_PORT=5432
API_URL=http://localhost:3000
LOG_LEVEL=debug
Production
# .env.production
NODE_ENV=production
DB_HOST=prod-db.example.com
DB_PORT=5432
API_URL=https://api.example.com
LOG_LEVEL=error
Load Based on Environment
const path = require('path');
const dotenv = require('dotenv');
const envFile = `.env.${process.env.NODE_ENV || 'development'}`;
dotenv.config({ path: path.resolve(process.cwd(), envFile) });
console.log(`Running in ${process.env.NODE_ENV} mode`);
6. Variable Types
String Values
APP_NAME=MyApp
API_KEY=abc123xyz
console.log(process.env.APP_NAME); // 'MyApp'
Numbers
PORT=3000
MAX_CONNECTIONS=100
// Convert to number
const port = parseInt(process.env.PORT, 10);
const maxConn = Number(process.env.MAX_CONNECTIONS);
Boolean Values
DEBUG=true
ENABLE_CACHE=false
const debug = process.env.DEBUG === 'true';
const enableCache = process.env.ENABLE_CACHE === 'true';
JSON Values
# Not recommended, but possible
CONFIG_JSON='{"key":"value","nested":{"prop":true}}'
const config = JSON.parse(process.env.CONFIG_JSON);
7. Default Values
const {
PORT = 3000,
DB_HOST = 'localhost',
NODE_ENV = 'development',
} = process.env;
console.log(PORT); // Uses 3000 if PORT not set
8. Validation
Manual Validation
require('dotenv').config();
const requiredEnvVars = [
'DB_HOST',
'DB_USER',
'DB_PASSWORD',
'JWT_SECRET',
];
for (const envVar of requiredEnvVars) {
if (!process.env[envVar]) {
throw new Error(`Missing required environment variable: ${envVar}`);
}
}
With envalid
npm install envalid
require('dotenv').config();
const { str, port, num, bool } = require('envalid');
const env = require('envalid').cleanEnv(process.env, {
NODE_ENV: str({ choices: ['development', 'test', 'production'] }),
PORT: port({ default: 3000 }),
DB_HOST: str(),
DB_PORT: num({ default: 5432 }),
ENABLE_HTTPS: bool({ default: false }),
});
console.log(env.PORT); // Validated and converted to number
9. Security Best Practices
1. Never Commit .env
# .gitignore
.env
.env.local
.env.*.local
2. Provide .env.example
# .env.example (commit this!)
DB_HOST=localhost
DB_USER=your_db_user
DB_PASSWORD=your_db_password
JWT_SECRET=your_secret_key
PORT=3000
3. Rotate Secrets Regularly
# Update secrets periodically
JWT_SECRET=new_secret_$(date +%s)
4. Use Strong Secrets
// Generate strong secret
const crypto = require('crypto');
const secret = crypto.randomBytes(64).toString('hex');
console.log(secret);
5. Restrict File Permissions
chmod 600 .env # Only owner can read/write
10. Production Deployment
Docker
# Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
# Don't copy .env - use environment variables
CMD ["node", "index.js"]
# docker-compose.yml
version: '3'
services:
app:
build: .
environment:
DB_HOST: postgres
DB_USER: admin
DB_PASSWORD: ${DB_PASSWORD}
env_file:
- .env
Heroku
# Set via CLI
heroku config:set DB_HOST=postgres.heroku.com
heroku config:set DB_PASSWORD=secret
# Or via dashboard
# Settings > Config Vars
Vercel
# .vercel.json (don't commit secrets!)
# Or use Vercel dashboard
vercel env add DB_PASSWORD
AWS/GCP
Use secrets managers:
const { SecretsManagerClient } = require('@aws-sdk/client-secrets-manager');
async function getSecret(secretName) {
const client = new SecretsManagerClient({ region: 'us-east-1' });
const response = await client.send(
new GetSecretValueCommand({ SecretId: secretName })
);
return JSON.parse(response.SecretString);
}
11. Real-World Example
// config.js
require('dotenv').config();
const config = {
app: {
name: process.env.APP_NAME || 'MyApp',
port: parseInt(process.env.PORT, 10) || 3000,
env: process.env.NODE_ENV || 'development',
},
db: {
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT, 10) || 5432,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
name: process.env.DB_NAME,
},
jwt: {
secret: process.env.JWT_SECRET,
expiresIn: process.env.JWT_EXPIRES_IN || '1h',
},
redis: {
host: process.env.REDIS_HOST || 'localhost',
port: parseInt(process.env.REDIS_PORT, 10) || 6379,
},
email: {
host: process.env.EMAIL_HOST,
port: parseInt(process.env.EMAIL_PORT, 10) || 587,
user: process.env.EMAIL_USER,
password: process.env.EMAIL_PASSWORD,
},
};
// Validate critical vars
if (!config.jwt.secret) {
throw new Error('JWT_SECRET is required');
}
module.exports = config;
// app.js
const config = require('./config');
const express = require('express');
const app = express();
app.listen(config.app.port, () => {
console.log(`${config.app.name} running on port ${config.app.port}`);
});
12. TypeScript Integration
// env.d.ts
declare global {
namespace NodeJS {
interface ProcessEnv {
NODE_ENV: 'development' | 'production' | 'test';
PORT: string;
DB_HOST: string;
DB_USER: string;
DB_PASSWORD: string;
JWT_SECRET: string;
}
}
}
export {};
// config.ts
import 'dotenv/config';
interface Config {
port: number;
database: {
host: string;
user: string;
password: string;
};
}
const config: Config = {
port: parseInt(process.env.PORT, 10),
database: {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
},
};
export default config;
13. Troubleshooting
Variables Not Loading
// Debug mode
require('dotenv').config({ debug: true });
// Check if .env exists
const fs = require('fs');
if (!fs.existsSync('.env')) {
console.error('.env file not found!');
}
Override Existing Variables
// Force override (not recommended)
require('dotenv').config({ override: true });
Encoding Issues
// Specify encoding
require('dotenv').config({ encoding: 'utf8' });
Summary
dotenv simplifies environment management:
- Keep secrets out of code
- Different configs per environment
- Easy local development
- Production-ready
- Zero dependencies
Key Takeaways:
- Never commit .env files
- Provide .env.example
- Validate required variables
- Use platform vars in production
- Rotate secrets regularly
Next Steps:
- Build with Node.js
- Deploy with Docker
- Secure with Security Guide
Resources:
Frequently Asked Questions (FAQ)
Q. When would I use this in practice?
A. Complete dotenv guide for managing environment variables. Learn .env files, secrets management, multi-environment setup,…
Q. What should I read before this?
A. Follow the previous article or related articles links at the bottom of each post to learn in sequence.
Q. Where can I study this more deeply?
A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.
Related Articles (Internal Links)
Other articles related to this topic.
- PM2 Complete Guide | Production Process Manager for Node.js
- Python Web Deployment | Heroku, AWS, and Docker in Practice
- Docker Compose Complete Guide | Multi-Container Apps, Networks, Volumes & Environment Variables
Keywords Covered in This Article (Related Search Terms)
This article covers dotenv, Environment Variables, Node.js, Security, Configuration, DevOps.