NestJS Configuration Manager
Flexible, Docker-friendly, Dotenv-based Configuration Module for NestJS
- Docker-friendly: e.g., use
.envfiles in dev/test, environment variables in production, or any combination
- @hapi/joi-based validation of environment variables
- Completely dynamic and customizable determination of the name/location of your
- means: no code changes to handle unique configs per environment
- Default values (i.e., optional environment variables with default values)
- Trace how an environment variable was resolved (i.e., came from external environment,
.envfile or as a default value) to help debug tricky problems between dev, test, production
- Why another NestJS configuration module?
- How it works
- Module configuration options
- Debug Switches
- Use with Docker
- Full Tutorial
Quick Start - Read This First
The package has one global Nest module (
ConfigManagerModule), and one main class (
ConfigManager) that you'll need to work with. The main idea is to create your own ConfigService (in the examples, we'll call it
ConfigService, but you can call it whatever you want). You probably want this in its own module (in the examples,
we'll call it
ConfigModule), which you probably want to be global. You'll then provide your
ConfigService for use in the rest of your application. This approach affords you a great deal of flexibility:
- Centralized setup of the
- Use Dependency Injection to provide the service wherever needed
- Easily override/mock the service for testing
- Future-proof: if you later want to switch to another 3rd party config module, your dependencies are isolated in one place
Following these conventions, your
ConfigModule might look like this:
This imports and registers the
register() method is how you
configure the module.
In this example, we explicitly provide a full path to the
.env file via the
useFile configuration option.
This is simple, but not terribly flexible. We'll explore more flexible options
below. When using a static file path with
useFile, the path is relative
to the root directory for the project, or the root directory in which the app is
running (in test and production environments). For example, if the app currently
has a structure like:
myproject├── src│ └── module1├── dist├── node_modules├── test├── config| └── development.env└── package.json
useFile configuration method would result in the
looking for a
dotenv-formatted file in:
ConfigService might look like this:
ConfigService (you can choose any name you want) is a derived
class that extends the
ConfigManager class provided by the package. You must
provideConfigSpec() method. This is where you define your schema.
Read more about schemas here.
With this in place, you can use your
ConfigService anywhere in your project. For example, assuming
.env file like:
A service could then use it like this:
getHello() would return
Hello johnwhen run with this configuration.
Dynamic env file location example
Let's say you have two environments: development and test, and want to set up your
ConfigService to dynamically locate the
.env file that is appropriate to each environment.
Let's assume that development uses one set of database credentials, and test uses another.
This would be well represented by having two
.env files. Perhaps they're stored in a folder like
myproject/config (this is just an example; they can be stored wherever you want). The files might look like:
How can we accommodate this dynamic file location without modifying our code?
useFile() method of configuration shown above won't work for this. You need
a way to read a different
.env file for each environment. A typical
approach is to use a specific environment variable (typically
NODE_ENV, though you can choose whatever you want) to indicate what the
active environment is. For example, when
running in development, you'd have
NODE_ENV equal to
NODE_ENV's value would equal
Based on this, you can use the
useEnv method of configuring the
useEnv method is described in the
Module Configuration Options
section, but a simple example is shown below.
To accommodate this requirement, we'd modify the way we register the
as follows, replacing
If instead of
NODE_ENV we wanted to use an environment variable like
MY_ENVIRONMENT to signify which environment we're running (e.g.,
MY_ENVIRONMENT is equal to
development when we're in our development
environment), we'd identify that environment variable using the option
as shown below:
Completely custom env file location
useEnv method provides significant flexibility, but more complex structures
require an even more flexible approach. To handle arbitrarily complex
environments, a third method,
useFunction, is available to write custom
This is covered in
Using a custom function.
See Changelog for more information.
Contributions welcome! See Contributing.
- John Biundo (Y Prospect on Discord)
Licensed under the MIT License - see the LICENSE file for details.