dotenv
is a popular Node.js package that loads environment variables from a .env
file into process.env
. TypeScript, on the other hand, is a typed superset of JavaScript that adds static type checking, enhancing code reliability and maintainability. However, when using dotenv
with TypeScript, developers often encounter the issue of undefined
values, which can lead to runtime errors. This blog post aims to explore the fundamental concepts behind this problem, provide usage methods, common practices, and best practices to help you handle these issues effectively.dotenv
dotenv
is a zero-dependency module that loads environment variables from a .env
file into process.env
. A .env
file typically contains key - value pairs, for example:
API_KEY=your_api_key
DB_USER=db_user
DB_PASSWORD=db_password
To use dotenv
in a Node.js project, you need to install it first:
npm install dotenv
Then, in your JavaScript or TypeScript file, you can load the environment variables as follows:
import dotenv from 'dotenv';
dotenv.config();
// Access an environment variable
const apiKey = process.env.API_KEY;
console.log(apiKey);
undefined
TypeScript is statically typed, which means it requires you to define the types of variables. When you access process.env
in TypeScript, the type of process.env
is NodeJS.ProcessEnv
, which has a type definition like this:
interface ProcessEnv {
[key: string]: string | undefined;
}
This means that any environment variable accessed through process.env
can be either a string or undefined
. If the corresponding environment variable is not set in the .env
file or the environment, TypeScript will correctly infer its type as undefined
.
dotenv
:npm install dotenv
.env
file:
Create a .env
file in the root directory of your project and add your environment variables:PORT=3000
dotenv
in your TypeScript file:import dotenv from 'dotenv';
dotenv.config();
const port = process.env.PORT;
console.log(port);
To avoid dealing with undefined
issues, you can create a custom type for your environment variables. For example:
import dotenv from 'dotenv';
dotenv.config();
// Define a custom type for environment variables
type CustomEnv = {
PORT: string;
};
// Assert that process.env has the custom type
const env = process.env as CustomEnv;
const port = env.PORT;
console.log(port);
undefined
Before using an environment variable, it’s a good practice to check if it’s undefined
. For example:
import dotenv from 'dotenv';
dotenv.config();
const apiKey = process.env.API_KEY;
if (apiKey === undefined) {
throw new Error('API_KEY is not set in the environment.');
}
// Now you can safely use apiKey
console.log(apiKey);
You can provide default values for environment variables in case they are not set. For example:
import dotenv from 'dotenv';
dotenv.config();
const port = process.env.PORT || '3000';
console.log(port);
Create a separate module to manage your environment variables. This makes it easier to handle and type-check them.
env.ts
:
import dotenv from 'dotenv';
dotenv.config();
// Define a custom type for environment variables
type CustomEnv = {
PORT: string;
API_KEY: string;
};
// Assert that process.env has the custom type
const env = process.env as CustomEnv;
// Function to get environment variables with validation
const getEnv = (key: keyof CustomEnv): string => {
const value = env[key];
if (value === undefined) {
throw new Error(`Environment variable ${key} is not set.`);
}
return value;
};
export const PORT = getEnv('PORT');
export const API_KEY = getEnv('API_KEY');
app.ts
:
import { PORT, API_KEY } from './env';
console.log(PORT, API_KEY);
In production, it’s recommended to set environment variables directly in the deployment environment rather than relying solely on the .env
file. For example, in a Docker container, you can set environment variables using the ENV
instruction in the Dockerfile or the -e
flag when running the container.
Using dotenv
with TypeScript can be tricky due to the undefined
issue. However, by understanding the fundamental concepts, following the usage methods, common practices, and best practices outlined in this blog post, you can effectively manage environment variables in your TypeScript projects. Always remember to check for undefined
values, provide default values when necessary, and centralize your environment variable management for better code organization and maintainability.