Jan 15, 2023
4 min read
Nest Js #4: How to Store, Read and Validate Environment Variable Using @nestjs/config
#nestjs
#javascript
#typescript
#backend
#api
Hi There! š
Usually, when you are working on a project you are not going to write code for all the features you are developing, sometime you might use third-party tools or services like AWS, SendGrid, Google Cloud, etcā¦
And these platforms will provide some secret or API keys to access the service and If you hardcode these keys on your code, there is a chance that anyone can misuse it.
So as a best practice, you should never hardcode these keys in code or push these keys to GitHub or any cloud repositories.
Instead, store these keys in the environment file and remember you shouldn't push this file to the repository.
In Node.js applications, it's common to useĀ .env files, holding key-value pairs where each key represents a particular value.
Before we get started with the implementation. Make sure you have a Nest Js project with these dependencies
# yarn
yarn add @nestjs/config class-validator class-transformer
# npm
npm i @nestjs/config class-validator class-transformer -s
Store Environment Variables
Create a file .env
at the root level of the project
Add your secret keys to the .env
file
# .env
SECRET_KEY="This is a Secret Key"
Great! You have created your environment variable.
To avoid pushing the .env
file to the repository. Add .env
to .gitignore
file
Setting Up Nest ConfigĀ Module
If you haven't installed the dependency that I mentioned at the begining of this tutorial. please install.
Once Installed
Import ConfigModule in app.module.ts
// App.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [ConfigModule.forRoot()], // Import ConfigModule
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
The forRoot()
method registers the ConfigService
provider which provides a get()
method to read the environment variables.
Since @nestjs/config
uses dotenv
library under the hood, by default forRoot()
the method will search forĀ .env
in the root of the project.
If you have named your environment file with a different name likeĀ .dev.env
then you need to pass the file name to the forRoot()
method
ConfigModule.forRoot({
envFilePath: '.dev.env',
})
Pro Tip If you want to use ConfigService in other modules you have to import ConfigModule again, To avoid importing in multiple modules and to globalise ConfigModule you can set isGlobal to true
ConfigModule.forRoot({
envFilePath: '.dev.env',
isGlobal: true
})
Reading Environment Variables Using ConfigService
To read environment variable value, we need to inject ConfigService
which is already registered by ConfigModule
that we imported in the app.module.ts
In my project, I want to read environment variable in the app.service.ts
file, So injecting ConfigService
in it. You can inject where ever you need.
// app.service.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class AppService {
constructor(private readonly configService: ConfigService) {}
getSecretKey(): string {
return this.configService.get('SECRET_KEY'); // read environment variable
}
}
Use get()
and pass the variable name that you want to read.
Validating Environment Variables
ConfigModule
provides an additional option to validate the environment variables by passing custom validation functions.
Why validation is required?
If you are working on a team and any developer miss any variable in theĀ .env
file, that might break the application.
Make sure you have installed the required dependencies class-validator
and class-transformer
Create a file environment.validation.ts
Add a class EnvironmentVariables
with all the variables that you have in theĀ .env
file
// environment.validation.ts
import { IsString } from 'class-validator';
class EnvironmentVariables {
@IsString({ message: 'Invalid SECRET_KEY' })
SECRET_KEY: string;
}
Now create the validation function
// environment.validation.ts
export const validate = (config: Record<string, unknown>) => {
// 'plainToClass' to converts plain object into Class
const validatedConfig = plainToClass(EnvironmentVariables, config, {
enableImplicitConversion: true,
});
// 'validateSync' method validate the class and returns errors
const errors = validateSync(validatedConfig, {
skipMissingProperties: false,
});
if (errors.length > 0) {
throw new Error(errors.toString());
}
return validatedConfig;
};
Import the validate functions in app.module.ts
and pass it to ConfigModule
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
import { validate } from './environment.validation';
@Module({
imports: [
ConfigModule.forRoot({
validate,
}),
], // Import ConfigModule
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Time ForĀ Testing
I am running my server at http://localhost:3000
Use any API testing tool like(postman
) to test the API.
And you can see when I hit my API, I am getting the secret key stored in theĀ .env
file as the response.