NestJS Configuration Secrets Made Easy with configify
Tags: nestjs, aws, ssm, config
Published: 2024-01-16 22:35:21

If you have been working with NestJS you are probably familiar with NestJS [config](https://github.com/nestjs/config) module.

The config module handles multi environment configurations and allows users to extend the module by providing customized configurations(e.g.: loading secrets from AWS Secrets Manager).

Another module that attempts to make it easier to deal with configurations and secrets is the [**configify**](https://github.com/it-gorillaz/configify) module. This module  offers a decorator based config mapping and an out of the box integration with AWS Secrets Manager and Parameter Store.

In this post we will be taking a look on how to use the **configify** module.

## Setup

Add the configify dependency to your project:

```
npm install --save @itgorillaz/configify
```

You can then import the module in your application module:

```js
@Module({
  imports: [ConfigifyModule.forRootAsync()],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
```

## Mapping Configuration Files

By default, configify will lookup for a `.env` or an `application.yml` file located in the root folder of the project.

So let's define our `.env` file:
```
# database configuration
DB_HOST=localhost
DB_PORT=3306
DB_USERNAME=admin
DB_PASSWORD=${AWS_SECRETS_MANAGER_DB_PASSWORD}

# api client configuration
API_CLIENT_ID=1234
API_CLIENT_SECRET=${AWS_PARAMETER_STORE_API_CLIENT_SECRET}

# aws secrets manager
AWS_SECRETS_MANAGER_DB_PASSWORD=my-secret-id

# aws parameter store
AWS_PARAMETER_STORE_API_CLIENT_SECRET=/secret/name
```

You can then define classes that will be mapped by the module according to your configuration file:

```js
@Configuration()
export class DatabaseConfiguration {
  @Value('DB_HOST')
  host: string;

  @Value('DB_PORT', {
    parse: (value: any) => parseInt(value)
  })
  port: number;

  @Value('DB_USERNAME')
  username: string;

  @Value('DB_PASSWORD')
  password: string;
}
```

```js
@Configuration()
export class ApiClientConfiguration {
  @Value('API_CLIENT_ID')
  host: string;

  @Value('API_CLIENT_SECRET')
  username: string;
}
```

By default, every environment variable prefixed with `AWS_SECRETS_MANAGER`, `AWS_PARAMETER_STORE`, `aws-secrets-manager` or `aws-parameter-store` will be considered a special attribute and the module will attempt to resolve it's remote value on AWS.

## Dependency Injection

The module will make the instances of your configuration classes globally available to the application, so in order to use it you just need to declare the dependency in the class constructor:

```js
export class AppService {
  private readonly LOGGER = new Logger(AppService.name);

  constructor(
    private readonly dbConfig: DatabaseConfiguration,
    private readonly apiConfig: ApiClientConfiguration,
  ) {
    this.LOGGER.log(JSON.stringify(dbConfig));
    this.LOGGER.log(JSON.stringify(apiConfig));
  }

}
```

## Module Options

You can provide your own instance of AWS Secrets Manager and Parameter Store client classes as well as override some other options offered by the module.

Check the [module's repository](https://github.com/it-gorillaz/configify) for a detailed documentation.