Step ahead fast, with NestJS environment configuration
Tags: nestjs, typescript, configuration
Published: 2022-01-26 09:48:42

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4n2mldbsoyc8vdpkchcb.png)

## Summary
Find how quickly you can start implementing your externally defined configuration settings in NestJS.

## Intro
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)
- etc.,

[NestJS](https://docs.nestjs.com) provides the necessary [documentation](https://docs.nestjs.com/techniques/configuration) 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](https://www.npmjs.com/package/@nestjs/config) package for your project and it is also good if you have also installed the [@nestjs/jwt](https://www.npmjs.com/package/@nestjs/jwt) package and started working with [JSON Web tokens](https://jwt.io/).

So, below you can find 3 of the most simple and common cases to use in your implementation(s).

---

## The basics
The .env.dev environment configuration file with defined properties and their values (like key/value pairs)

The .env.dev

```
APP_PORT=3000
APP_GLOBAL_PREFIX=tickets
JWT_SECRET=abcdABCD1234554321
JWT_EXP=3600s
```
The scripts in the package.json file

```
. . .
    "start:dev": "STAGE=dev nest start --watch",
    "start:debug": "STAGE=debug nest start --debug --watch",
    "start:prod": "STAGE=prod node dist/main",
. . .
```
For instance, we can run the dev configuration in our terminal by

```npm run start:dev```

**Configuring the ConfigModule globally in the AppModule**
{% gist https://gist.github.com/zzpzaf/f8eb518bd0e7251b0aeda7454277e6de %}

.forRoot()
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.

isGlobal
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.

envFilePath
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.

First, we have to add it in the imports property array of the Module that this clas/property/service belongs to.

```imports: [AuthModule, ConfigModule],```

**Declaring (Importing) the ConfigModule in the UsersModule**
{% gist https://gist.github.com/zzpzaf/479149be37cff7840daffb4550d9b4f7 %}

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:
{% gist https://gist.github.com/zzpzaf/9c43b82b997af9a6453e5f4491b2dec7 %}
And finally, we can use it ‘normally’:
{% gist https://gist.github.com/zzpzaf/1bea152ff86ee3a97517e8544bcd0494 %}

---

## 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**
{% gist https://gist.github.com/zzpzaf/83063a5478eed5c17ad919024f3c94db %}

---

## 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**
{% gist https://gist.github.com/zzpzaf/6cb35effd21166290682b662731355cf %}
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.

---

That’s it!
Thanks for reading and happy coding!