Mastering Environment Variables in NestJS

Abdullah Irfan
5 min readOct 22, 2023

--

Photo generated by Bing

This is second article of series Building a Robust Backend: A Comprehensive Guide Using NestJS, TypeORM, and Microservices.
The setup and management of environment variables are paramount in developing applications that are adaptable across various stages of deployment. Let’s delve deeper into this topic to understand their significance, especially in the context of the NestJS framework.
If you don’t have any idea about environment variables, keep reading otherwise skip to the setting up environment variables.

What are environment variables and why are they important?
Environment variables are dynamic values that can influence how running processes behave on a computer. They’re often used in development to separate concerns between different aspects of an application. For instance, an app might connect to different databases when in development, testing, or production. By leveraging environment variables, developers can ensure the right configurations are used for the right environments, thus promoting code modularity and preventing potential deployment issues.

What is a system environment variable? What is `.env`?
A system environment variable is set and accessed at the operating system level; it’s available for all processes running under the OS. On the other hand, a .env file is a plain-text file used to store environment variables specifically for a project. Instead of managing environment variables at the system level, developers can define them in a .env file at the project’s root, ensuring they’re isolated to that particular application.

Setting up dynamic environment variables in NestJS
Now we have clear understanding of environment variables and their importance, lets proceed with setting it up in our previous code (https://github.com/AbdullahDev0/medium-nestjs/tree/feature/configure-postgres-db).

To manage different settings, we’ll use files named local.env, development.env, and production.env. We'll also have a main .env file that tells us which setting we're using, like NODE_ENV=development. To keep things tidy, we'll put shared code in a shared folder, with utility functions in a utils subfolder. Inside, a config.ts file will help us pick the right settings based on the environment we're in. The provided code shows how this works.

import * as dotenv from 'dotenv'; // Import the dotenv library
import * as fs from 'fs'; // Import the filesystem library

export function loadConfig() {
const environment = process.env.NODE_ENV || 'local'; // Determine the current environment, defaulting to 'local'

// Read and parse the .env file associated with the current environment
const data: any = dotenv.parse(fs.readFileSync(`${environment}.env`));

// Set the parsed variables to the process.env
for (const key in data) {
if (Object.prototype.hasOwnProperty.call(data, key)) {
process.env[key] = data[key];
}
}
}

Though not related, but here issue that you might face is from ESLint like image below:

ESLint error of endline

When ESLint gives errors that aren’t real problems, it’s annoying. To fix this, we need to tell ESLint to be less strict about line endings. Just open the .eslintrc.js file and add the code shown in the picture to the rules. This will stop those false errors.

    "prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
]
Add ESLint rule

Now lastly import the loadConfig() function in main.ts and call the function in the beginning. Another way of loading the required.env file is by loading the file in dotenv.config() the final code should look like below snippet:

// Loading config before anything
import { loadConfig } from './shared/utils/config';
loadConfig();

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as dotenv from 'dotenv';

// Another way of loading env file, use as per your preference
const environment = process.env.NODE_ENV || 'local';
dotenv.config({ path: `${environment}.env` });

async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(process.env.PORT || 3000);
}
bootstrap();

Finally create a .env file in main directory and define NODE_ENV=local, further create local.env and define PORT in it like PORT=5000. Now by default when a NestJS app is creates, it has app module, controller and service, and controller has a GET route that calls service getHello() function which responds with Hello World! string, however, controller and services aren’t provided to the module so add them as controller and provider. The app.module.ts should look be like code snippet below:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgres',
password: 'admin',
database: 'gmail-sync',
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

Lastly start the application again using npm start and on hitting http://localhost:5000 it should respond with Hello World! That’s it folks, we have successfully configured dynamic .env variables for our application. in next story we will discuss about creating new route, setting up DTOs, entities, and other stuff. This story code is available on GitHub in feature/setting-environment-variables branch. If you appreciate this work, please show your support by clapping for the story and starring the repository.

Before we conclude, here’s a handy toolset you might want to check out: The Dev’s Tools. It’s not directly related to our tutorial, but we believe it’s worth your attention. The Dev’s Tools offers an expansive suite of utilities tailored for developers, content creators, and digital enthusiasts:

  • Image Tools: Compress single or multiple images efficiently, and craft custom QR codes effortlessly.
  • JSON Tools: Validate, compare, and ensure the integrity of your JSON data.
  • Text Tools: From comparing texts, shuffling letters, and cleaning up your content, to generating random numbers and passwords, this platform has got you covered.
  • URL Tools: Ensure safe web browsing with the URL encoder and decoder.
  • Time Tools: Calculate date ranges and convert between Unix timestamps and human-readable dates seamlessly.

It’s a treasure trove of digital utilities, so do give it a visit!

--

--