NestJS is a framework in Node.js for building efficient, scalable server-side applications and also supports Typescript 😍
In this article I’ll show you how to set up the Environment Variables. These variables are used to store sensitive information, secrets and configuration data. Having this information hardcoded in your code is a huge security flaw and not a best practice.
Without further ado, let’s begin!
Set up a .env file
Let’s start by creating the most popular file to store and manage our Environment Variables, a file named .env
at the root of your project. Here’s some example variables:
PORT=5000
NODE_ENV=development
API_URL=https://api.com
MONGODB_CONNECTION_STRING=mongodb@clusterdatabase
If you are working with git (version control system), you should keep all your .env files out of version control, as it’s not information we want to share or upload to an open-source platform like GitHub. This means you avoid sharing all sensitive information with the whole world!
Always add your .env
files to your .gitignore
.env.local
.env.development.local
.env.test.local
.env.production.local
Custom Configuration file and ConfigProps
In the previous step we created a .env
file with several Environment Variables, so the main idea for this step is to create a single directory for handling those variables. Instead of calling process.env
in all the files we need, we’re going to create a custom configuration file. These files will return a nested object grouped by functions (settings, database), which will allow us to manage our variables in a more independent and orderly way. In the future, if we need to change some name or value, it will be as simple as opening a single file.
Let’s create in the src
directory the next folders and files
src
├── config
│ └── config.ts
├── interfaces
│ └── config.interface.ts
The interface it’s going to be the structure type-checking for our config.ts
file, once created we just need to export it.
config.interface.ts
interface ApiConfigProps {
apiUrl: string
httpTimeout: number
}
interface MongodbConfigProps {
connectionString: string
databaseName: string
}
export interface ConfigProps {
port: number
api: ApiConfigProps
mongodb: {
database: MongodbConfigProps
}
}
config.ts
export const config = ():ConfigProps => ({
port: parseInt(process.env.PORT, 10) || 8080,
api: {
apiUrl: process.env.API_URL,
httpTimeout: 1000,
},
mongodb: {
database: {
connectionString: process.env.MONGODB_CONNECTION_STRING || 'mongodb://localhost:27017',
databaseName: process.env.NODE_ENV || 'local'
}
}
});
NestJS configuration
To begin, we need to start by installing the required dependency.
npm i --save @nestjs/config
Once we have it installed, we import it in our root module AppModule, it's important to add it along with the method .forRoot()
, as this method will allow us to register our ConfigService
as a provider (dependency injection) and give us access to the .get()
method which we will see later.
In order to use the custom config file globally in our application, we have to add a couple of settings to our ConfigModule options object. This is how should look like:
import { ConfigModule } from '@nestjs/config';
import { config } from './config/configuration';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
load: [config]
})]
})
export class AppModule {}
Using ConfigService in main.ts
As we already have everything correctly configured, we can now access all the values in the config file. In the main.ts
file, the PORT value is hardcoded by default. This value should be assigned to an Environment Variable and not have it written directly in the code, so we are going to change it by using the one that we have saved in the ConfigService
.
import { ConfigService } from '@nestjs/config';
const configService = app.get(ConfigService);
const port = configService.get<number>('port');
await app.listen(port);
Logger.log(`~ Application is running on: ${await app.getUrl()}`);
Use ConfigService in modules
For using our config file in a module we only have to import the ConfigService
and access the method .get()
. Let’s use as example an HTTP client module as is HTTP module, which is basically a module that wraps Axios and exposes all the methods to be able to use them.
We are going to declare our HTTP module and pass options asynchronously with the values from our config
file by adding a factory provider to inject dependencies.
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
ConfigModule,
HttpModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
baseURL: configService.get<string>('api.apiUrl'),
timeout: configService.get<number>('api.httpTimeout')
}),
inject: [ConfigService]
})
]
})
Using ConfigService in providers
To conclude, we will give an example of how to integrate our config file in a provider such as the database. For this we are going to use the object modeling tool Mongoose, one of the methods that NestJs supports to integrate with MongoDB database.
export const databaseProviders = [
{
imports: [ConfigModule],
provide: 'CONNECTION',
useFactory: async (configService: ConfigService): Promise<typeof mongoose> => {
const connectionData = {
host: configService.get<string>('mongodb.database.connectionString'),
databaseName: configService.get<string>('mongodb.database.databaseName')
};
const connection = await mongoose.connect(`${connectionData.host}`);
return connection;
},
inject: [ConfigService]
},
];
Thank you all very much for reading this article and I hope it helps you create great applications and please let me know in the comments what you think about this post or if you have any questions. Thank you so much for reading!
Thank you all and happy coding!🖖
Top comments (1)
You have forgotten to provide configuration for package.json, above code will work but with default configuration from .env file not local, test or prod file