Node.js Environment Variables
Environment variables are key-value pairs stored outside of the application's source code — in the operating system or in a special configuration file — that the application can read at runtime. They are used to store sensitive or environment-specific information such as database passwords, API keys, port numbers, and secret tokens.
The core principle is simple: code that is shared (e.g., pushed to GitHub) should never contain secrets. Environment variables keep sensitive configuration separate from the codebase.
Why Are Environment Variables Important?
- Security: Passwords, API keys, and tokens are not stored in code files that might be publicly visible.
- Flexibility: The same code can run in different environments (development, testing, production) with different configurations — without changing the code itself.
- Best Practice: Separating configuration from code is a widely recognized software engineering principle.
Accessing Environment Variables with process.env
Node.js makes all environment variables available through the process.env object:
// Reading an environment variable
const port = process.env.PORT;
console.log("Port:", port);
Environment variables can be set directly in the terminal before running a script:
# On macOS/Linux
PORT=5000 node app.js
# On Windows (Command Prompt)
set PORT=5000 && node app.js
The dotenv Package
Setting variables in the terminal every time is impractical. The dotenv package allows environment variables to be loaded from a .env file automatically.
Installing dotenv
npm install dotenv
Creating the .env File
Create a file named .env in the project root directory:
# .env
PORT=3000
NODE_ENV=development
DB_URI=mongodb+srv://admin:secretpassword@cluster.mongodb.net/myapp
JWT_SECRET=mySuperSecretKey_DoNotShare
API_KEY=abc123xyz789
- Each line has the format
KEY=VALUE. - No spaces around the equals sign.
- Comments start with
#. - Values do not need quotes (unless the value contains spaces).
Loading the .env File in the Application
Load dotenv at the very top of the entry file (app.js or index.js), before any other code:
// app.js
require('dotenv').config();
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
const DB_URI = process.env.DB_URI;
const JWT_SECRET = process.env.JWT_SECRET;
console.log("Environment:", process.env.NODE_ENV);
console.log("Server starting on port:", PORT);
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});
|| 3000 provides a fallback value in case the environment variable is not defined.
Never Commit the .env File to Git
The .env file contains sensitive credentials and must never be uploaded to version control. Add it to the .gitignore file:
# .gitignore
node_modules/
.env
Sharing Configuration Without Exposing Secrets
Instead of sharing the actual .env file, a template file (.env.example) is shared with all the variable names but no real values:
# .env.example
PORT=
NODE_ENV=
DB_URI=
JWT_SECRET=
API_KEY=
Anyone who clones the project copies this file to .env and fills in their own values.
Using Environment Variables in a Full Application
// app.js
require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const app = express();
app.use(express.json());
// Connect to database using env variable
mongoose.connect(process.env.DB_URI)
.then(() => console.log('Database connected'))
.catch(err => console.log('DB error:', err.message));
// Route protected by an API key check
app.get('/api/data', function(req, res) {
const clientKey = req.headers['x-api-key'];
if (clientKey !== process.env.API_KEY) {
return res.status(401).json({ error: 'Invalid API key' });
}
res.json({ message: 'Access granted', data: [1, 2, 3] });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Running in ${process.env.NODE_ENV} mode on port ${PORT}`));
Environment-Specific Behavior
The NODE_ENV variable is a widely used convention to identify the current environment:
if (process.env.NODE_ENV === 'development') {
console.log('Running in development mode — verbose logging enabled.');
}
if (process.env.NODE_ENV === 'production') {
console.log('Running in production mode — optimized for performance.');
}
Common values are development, test, and production. Libraries like Express and Mongoose also use NODE_ENV internally to adjust their behavior.
Setting Environment Variables in Production
In production environments (like a cloud server), environment variables are configured in the hosting platform's dashboard — not in a .env file. Common platforms include:
- Heroku: Set via the dashboard under Config Vars, or using the CLI:
heroku config:set KEY=VALUE - Railway: Set under the environment variables section of the project.
- AWS / Azure / GCP: Use their respective secrets management services.
- Vercel: Set in Project Settings → Environment Variables.
Validating Required Environment Variables on Startup
A good practice is to check that all required environment variables are present before the application starts:
require('dotenv').config();
const requiredVars = ['PORT', 'DB_URI', 'JWT_SECRET'];
requiredVars.forEach(function(varName) {
if (!process.env[varName]) {
console.error(`ERROR: Missing required environment variable: ${varName}`);
process.exit(1); // Stop the application
}
});
console.log('All required environment variables are set. Starting app...');
This prevents the application from starting in a broken state and provides a clear error message about what is missing.
Key Points
- Environment variables store sensitive and environment-specific configuration outside the codebase.
- Access all environment variables in Node.js through the
process.envobject. - The
dotenvpackage loads variables from a.envfile intoprocess.envat startup. - Always call
require('dotenv').config()at the very top of the entry file. - The
.envfile must be added to.gitignoreand never committed to version control. - Provide a
.env.exampletemplate file so collaborators know which variables are needed. - In production, environment variables are set in the hosting platform's settings — not in a
.envfile. - Always validate required variables on startup to catch configuration errors early.
