DEV Community

Cover image for Managing Environment Variables in Node.js with dotenv
Saiful Islam
Saiful Islam

Posted on

1

Managing Environment Variables in Node.js with dotenv

When developing applications in Node.js, managing sensitive configuration values securely is crucial. These values—such as API keys, database credentials, and server ports—are often stored in environment variables. The dotenv package allows us to load these variables from a .env file, keeping them out of our source code while still being accessible within our application.

In this article, we'll explore how to efficiently manage environment variables using dotenv and create a utility function to ensure that required variables are always available.


Why Use Environment Variables?

Using environment variables provides several benefits:

  • Security: Keeps sensitive information out of the codebase.
  • Configurability: Easily change settings without modifying code.
  • Environment-specific settings: Use different values for development and production environments.

Setting Up dotenv in a Node.js Project

Step 1: Install dotenv

Before we can use dotenv, we need to install it in our project:

npm install dotenv
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a .env File

In the root of your project, create a .env file and define your environment variables:

PORT=5000
FRONTEND_URL=http://localhost:3000
NODE_ENV=development
DB_CONNECT=mongodb://localhost:27017/mydatabase
ACCESS_TOKEN=your-secret-access-token
Enter fullscreen mode Exit fullscreen mode

Note: Never commit your .env file to a repository! Always add .env to your .gitignore file.


Loading Environment Variables in Node.js

We can use dotenv to load environment variables into our Node.js application. The following code demonstrates how to do this:

Step 3: Create a Configuration File

import { config } from "dotenv";

config({ path: "../../.env" });

// Define all required environment variables
const envVars = {
  port: process.env.PORT || 5000,
  frontendUrl: process.env.FRONTEND_URL,
  nodeEnv: process.env.NODE_ENV as "development" | "production",
  dbConnect: process.env.DB_CONNECT,
  accessToken: process.env.ACCESS_TOKEN,
};

/**
 * This function returns an environment variable and throws an error if unavailable.
 * @param varName - The key of the environment variable.
 * @returns The value of the specified environment variable.
 */
export default function getEnv(varName: keyof typeof envVars): string {
  if (typeof envVars[varName] === "undefined") {
    console.error(`'${varName}' is not available`);
    process.exit(1);
  } else {
    return envVars[varName] as string;
  }
}
Enter fullscreen mode Exit fullscreen mode

Understanding the Code

  1. Load environment variables:
import { config } from "dotenv";
config({ path: "../../.env" });
Enter fullscreen mode Exit fullscreen mode

This imports dotenv and loads the .env file into process.env.

  1. Define expected environment variables:
const envVars = {
  port: process.env.PORT || 5000,
  frontendUrl: process.env.FRONTEND_URL,
  nodeEnv: process.env.NODE_ENV as "development" | "production",
  dbConnect: process.env.DB_CONNECT,
  accessToken: process.env.ACCESS_TOKEN,
};
Enter fullscreen mode Exit fullscreen mode

We define a set of expected environment variables and provide a default value for PORT in case it is missing.

  1. Create a function to retrieve environment variables safely:
export default function getEnv(varName: keyof typeof envVars): string {
  if (typeof envVars[varName] === "undefined") {
    console.error(`'${varName}' is not available`);
    process.exit(1);
  } else {
    return envVars[varName] as string;
  }
}
Enter fullscreen mode Exit fullscreen mode

This function ensures that if an environment variable is missing, the application will throw an error and terminate instead of failing silently.


Using the getEnv Function

Now, whenever we need an environment variable in our project, we can safely retrieve it like this:

import getEnv from "./getEnv";

const databaseURL = getEnv("dbConnect");
console.log("Database URL:", databaseURL);
Enter fullscreen mode Exit fullscreen mode

If the variable is missing, the application will exit and log an error, ensuring we never run the app with missing configurations.


Best Practices for Managing Environment Variables

  1. Never hardcode secrets in your application. Always use environment variables.
  2. Use a .env.example file to provide a template for required variables.
  3. Use environment-specific .env files, such as .env.development and .env.production.
  4. Use a library like cross-env for setting environment variables in scripts across different operating systems.

Conclusion

Managing environment variables is an essential part of application development, and the dotenv package makes it easy to load them securely. By creating a structured approach using a getEnv function, we can ensure that all required variables are properly loaded, preventing runtime errors caused by missing configurations.

By following best practices, we can enhance the security, maintainability, and flexibility of our Node.js applications.


Full Code Example

import { config } from "dotenv";

config({ path: "../../.env" });

const envVars = {
  port: process.env.PORT || 5000,
  frontendUrl: process.env.FRONTEND_URL,
  nodeEnv: process.env.NODE_ENV as "development" | "production",
  dbConnect: process.env.DB_CONNECT,
  accessToken: process.env.ACCESS_TOKEN,
};

export default function getEnv(varName: keyof typeof envVars): string {
  if (typeof envVars[varName] === "undefined") {
    console.error(`'${varName}' is not available`);
    process.exit(1);
  } else {
    return envVars[varName] as string;
  }
}
Enter fullscreen mode Exit fullscreen mode

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay