Step ahead fast, with NestJS environment configuration
Find how quickly you can start implementing your externally defined configuration settings in NestJS.
You have probably spent some time working with the awesome NestJS framework and now it’s time to see how to get some externally defined values for your configuration settings like some key or global variables, e.g.:
- App listening port number
- API global route prefix
- JWT parameters (token secret, token expiration time, e.g. in seconds)
- Database connection parameters (type, host, port, username, password, database)
NestJS provides the necessary documentation for working with different environments (development, production, etc.) using external configuration files and environment variables. So, if you have already taken a look there, then the below provided cases, will give you a hand to start implementing your (relatively simple) project as well.
NB: It is supposed that you have already installed the @nestjs/config package for your project and it is also good if you have also installed the @nestjs/jwt package and started working with JSON Web tokens.
So, below you can find 3 of the most simple and common cases to use in your implementation(s).
The .env.dev environment configuration file with defined properties and their values (like key/value pairs)
The scripts in the package.json file
For instance, we can run the dev configuration in our terminal:
npm run start:dev
Configuring the ConfigModule globally in the AppModule
This static method loads the environment variables in the ConfigModule, configures the ConfigService provider and makes it module-wide, and since this is the AppModule, it makes it available across the app.
We use the isGlobal property and we set it to true, so we can use the ConfigModule generally in our project without to have to import it in each one module separately.
We use the envFilePath property to load the environment variables from a file – we pass the full-path name of the file containing them.
Now, it’s time to use the externally defined values (via the ConfigModule) in our project.
Using the ConfigService in a class/repo/service
First, we have to add it in the imports property array of the Module that this clas/property/service belongs to.
imports: [AuthModule, ConfigModule],
Importing the ConfigModule in the UsersModule
Note, that in our case, we have already set the ConfigModule for global use in our AppModule (i.e. we have set the isGlobal property to true), and thus, there is no need to import the ConfigModule in imports property array.
Then, we have to inject it in the constructor of that class/repo/service:
And finally, we can use it ‘normally’:
Using the ConfigService in the main.ts
Since the main.ts contains just the bootstrap() function, we can get the ConfigService instance/context as a const, like that:
const configService = app.get(ConfigService);
After that, we can use the get method of the instance, the normal way, e.g. for the application listening port:
const appPort = configService.get<number>('APP_PORT', 3000); await app.listen(appPort);
As you can see (and as the official documentation states) “The get() method also takes an optional second argument defining a default value, which will be returned when the key doesn’t exist, as shown” above for the application listening port, for which the default value is 3000.
The same we can do for any other key declared in an environment file.
An example of a main.ts file
Injecting and using the ConfigService in a dynamically imported module (that it is being imported in imports property array of a Module)
This is for instance the case when we import the JwtModule in another module, eg. in the Authorization module: AuthModule. Below, is how we can import the JwtModule and register directly the values of its parameters/properties: secret and expiresIn in signOptions.
A first hint here is to register the JwtModule Asynchronously, e.g.
JwtModule.registerAsync(. . .)
This is necessary because we have to read external files such as .env files asynchronously.
Then, we have to add the ConfigModule in the inject property array. After that we can provide/inject the ConfigService instance dynamically, (and asynchronously), using the useFactory().
An example of a full version of the AuthModule
Again here, there is no need to also declare the ConfigModule in the modules property array, since we have already set the isGlobal: true in AppModule.
Thanks for reading and happy coding!