Back to Blog
Lesson 30 of the Node.js: Build Your First Server & CLI course
Node.jsAugust 17, 20264 min read

Mastering Environment Variables in Node.js with dotenv

Stop hardcoding database credentials and API keys. Learn how to use dotenv to secure your Node.js application configuration with environment variables.

Node.jsdotenvsecurityconfigurationbackend
Focused view of a computer screen displaying code and debug information.

Previously in this course, we explored The OS and Process Modules, where we first encountered process.env. In that lesson, we learned that Node.js can read system-level variables, but relying on the operating system alone is brittle and difficult for local development.

Today, we are taking a crucial step in our project: moving our hardcoded database connection strings and secret keys into a dedicated configuration file using dotenv. This is a professional standard that keeps your credentials out of version control and allows your app to behave differently in development, testing, and production.

Why Use Environment Variables?

Hardcoding credentials like MONGO_URI='mongodb://localhost:27017/myapp' is a dangerous anti-pattern. If you push that code to a repository (like GitHub), anyone with access can compromise your database.

Environment variables allow us to:

  1. Decouple configuration from code: Your logic stays the same; only the settings change.
  2. Improve Security: Secrets never touch your Git history.
  3. Simplify Deployment: You can inject different values (like a production database URL) on platforms like Render without changing your source code.

Getting Started with dotenv

Wooden Scrabble tiles spelling 'Life Will Not Wait' on a white background.

The dotenv package is the industry standard for loading variables from a .env file into process.env.

1. Installation

In your project directory, install the package:

Bash
npm install dotenv

2. Creating the .env File

At the root of your project, create a file named .env. This file should never be committed to Git. Add your configuration values in KEY=VALUE format:

TEXT
# .env file
PORT=3000
DB_URI=mongodb://localhost:27017/my-rest-api
JWT_SECRET=supersecretkey123

3. Loading Variables

You must load dotenv as early as possible in your application. In your main entry file (e.g., index.js or app.js), add this at the very top:

JAVASCRIPT
require(CE9178">'dotenv').config();

const express = require(CE9178">'express');
const app = express();

// Now you can access your variables via process.env
const port = process.env.PORT || 8080;
const dbUri = process.env.DB_URI;

console.log(CE9178">`Server starting on port ${port}`);

Worked Example: Connecting to MongoDB

We previously learned about Connecting to MongoDB with Mongoose. Let’s refactor that connection to use our new environment variable:

JAVASCRIPT
// config/db.js
const mongoose = require(CE9178">'mongoose');

const connectDB = async () => {
  try {
    // We access the variable defined in our .env file
    await mongoose.connect(process.env.DB_URI);
    console.log(CE9178">'MongoDB Connected...');
  } catch (err) {
    console.error(err.message);
    process.exit(1);
  }
};

module.exports = connectDB;

Practice Exercise

  1. Add a new variable called NODE_ENV to your .env file and set it to development.
  2. In your main server file, add a condition: if process.env.NODE_ENV === 'development', log "Running in development mode" to the console.
  3. Crucial: Add .env to your .gitignore file immediately to ensure you don't accidentally leak your secrets.

Common Pitfalls

Close-up of a triangular warning sign indicating a slippery surface, fixed to a wooden post.

  • Committing the .env file: Always add .env to .gitignore. If you accidentally commit it, you must rotate your keys immediately, as they are now public.
  • Late loading: If you attempt to access process.env.DB_URI before calling require('dotenv').config(), the value will be undefined.
  • Missing Variables: If your application crashes because a variable is missing, implement a check at startup to ensure required environment variables are present, rather than letting the app fail silently later.

FAQ

Q: Can I use different .env files for different environments? A: Yes, though usually you define standard variables in .env and let your hosting provider (like Render or Heroku) override them via their dashboard interface.

Q: Should I put non-sensitive config in .env? A: It is a matter of preference, but many teams keep all "environment-specific" settings in .env to maintain a single source of truth for configuration.

Q: How do I share my .env file with teammates? A: Create a file called .env.example. This file contains the keys (e.g., DB_URI=) but no real values. Commit this to your repo so others know which variables they need to define locally.

Recap

Team members presenting a project in a modern office setting with a focus on collaboration.

By using dotenv, we've successfully decoupled our configuration from our source code. We've moved from hardcoded strings to a secure, environment-aware setup. This practice is essential for building production-ready APIs, similar to the techniques discussed in Using Environment Variables in Next.js: A Security Guide or Environment Variables: A Developer’s Guide to Shell Configuration.

Up next: We will learn how to verify our API endpoints reliably using Postman.

Similar Posts