npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@vinsidious/nestjs-config

v1.0.4

Published

Easy to use Nest congifuration module

Downloads

1

Readme

Note

This is a fork of the original nestjs-config which has been modified to use dotenv-flow instead of dotenv.

Features

  • Load your configurations with globs
  • Support for different environment configuration, thanks to dotenv
  • Change and Load configuration at runtime

Installation

Yarn

yarn add nestjs-config

NPM

npm install nestjs-config --save

Getting Started

Let's imagine that we have a folder called config in our project under src

/src
├── app.module.ts
├── config
│   ├── express.ts
│   ├── graphql.ts
│   └── grpc.ts

Let's register the config module in app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from "nestjs-config";

@Module({
    imports: [
        ConfigModule.load(),
    ],
})
export class AppModule {}

That's it!

Now let's say that your application isn't in a folder called src, it's in ./app.

import * as path from 'path';
import { Module } from '@nestjs/common';
import { ConfigModule } from "nestjs-config";

@Module({
    imports: [
        ConfigModule.load(
            path.resolve(__dirname, 'config/**/*.{ts,js}')
        ),
    ],
})
export class AppModule {}

We provide as first argument the glob of our interested configuration that we want to load.

Complex project structure

For example project has the next structure:

/
├── dist/
├── src/
│   ├── app/
│   │   ├── app.module.ts
│   │   └── bootstrap/
│   │   │   ├── index.ts
│   │   │   └── bootstrap.module.ts
│   ├── migrations/
│   ├── cli/
│   ├── config/
│   │   ├── app.ts
│   │   └── database.ts
│   └── main.ts
├── tsconfig.json
└── package.json

On this example, config files are located near the app folder, because they are shared between app, migrations and cli scripts.

Also during typescript compilation all files from src/ folder will be moved to the dist/ folder.

Moreover ConfigModule is imported in BootstrapModule, but not directly in AppModule.

// app.module.ts
import { Module } from '@nestjs/common';
import { BootstrapModule } from "./bootstrap";

@Module({
    imports: [BootstrapModule],
})
export class AppModule {}
// bootstrap.module.ts
import * as path from 'path';
import { Module } from '@nestjs/common';
import { ConfigModule } from "nestjs-config";

@Module({
    imports: [
      ConfigModule.load(path.resolve(__dirname, '../../config/**/*.{ts,js}')),
    ],
})
export class BootstrapModule {}

We still provide as first argument the glob of our configuration, but an example above looks a little bit ugly.

Also we will always have to remember about this glob path when we want to move the BootstrapModule to different place.

There is two ways to avoid such situations:

  • Explicitly set absolute path to the project sources from AppModule and use glob with relative path:

    // app.module.ts
    import { Module } from '@nestjs/common';
    import { ConfigService } from "nestjs-config";
    import * as path from "path";
    import { BootstrapModule } from "./bootstrap";
      
    ConfigService.srcPath = path.resolve(__dirname, '..');
      
    @Module({
        imports: [BootstrapModule],
    })
    export class AppModule {}
    // bootstrap.module.ts
    import { Module } from '@nestjs/common';
    import { ConfigModule } from "nestjs-config";
      
    @Module({
        imports: [
          ConfigModule.load('config/**/*.{ts,js}')
        ],
    })
    export class BootstrapModule {}
  • Invoke ConfigModule.resolveSrcPath(__dirname) from any your module before config loading and use glob with relative path.

    // bootstrap.module.ts
    import { Module } from '@nestjs/common';
    import { ConfigModule } from "nestjs-config";
      
    @Module({
        imports: [
          ConfigModule.resolveSrcPath(__dirname).load('config/**/*.{ts,js}')
        ],
    })
    export class BootstrapModule {}

On these examples we provide as first argument the glob of our configuration, but it is relative to the src/ folder.

Environment configuration

This package ship with the amazing dotenv so that you can create a .env file in your preferred location.

let's create one!

# .env

EXPRESS_PORT=3000

now in our src/config/express.ts file we can refer to that environment variable

// src/config/express.ts


export default {

    port: process.env.EXPRESS_PORT
}

Note: By default the package look for a .env file in the path that you started your server from. If you want to specify a path for your .env file use the second parameter of ConfigModule.load.

Usage

Now we are ready to inject our ConfigService everywhere we'd like.

import {ConfigService} from 'nestjs-config'


@Injectable()
class SomeService {

    constructor(private readonly config: ConfigService) {
        this.config = config;
    }
    
    isProduction() {
        
        const env = this.config.get('app.environment');
        
        return env === 'production';
    }
}

You can also use the @InjectConfig decorator instead, as following:

import {InjectConfig} from 'nestjs-config';


@Injectable()
class SomeService {

    constructor(@InjectConfig() private readonly config) {
        this.config = config;
    }
}

Customer Helpers

This feature allows you to create small helper function that computes values from configurations.

example isProduction helper:

// src/config/express.ts


export default {

    environment: process.env.EXPRESS_PORT
    port: process.env.EXPRESS_PORT,
    
    // helpers
    isProduction() {
        return this.get('express.environment') === 'production';
    }
}

usage:

this.config.get('express').isProduction();

// or

this.config._isProduction(); // note the underscore prefix.

Global Helpers

You can also attach helpers to the global instance as follow:


this.config.registerHelper('isProduction', () => {
    return this.get('express.environment') === 'production';
});

Then use it:

this.config.isProduction();

ConfigService API

get(param: string | string[], value: any = undefined): any

Get a configuration value via path, you can use dot notation to traverse nested object.

this.config.get('server.port'); // 3000

set(param: string | string[], value: any = null): Config

Set a value at runtime, it creates one if doesn't exists.

this.config.set('server.port', 2000); // {server:{ port: 2000 }}

has(param: string | string[]): boolean

Determine if the given path for a configuration exists and set

this.config.has('server.port'); // true or false

merge(glob: string, options?: DotenvOptions): Promise

You can load other configuration at runtime. Great for package development.

@Module({})
export class PackageModule implements NestModule {

    constructor(@InjectConfig() private readonly config) {}

    async configure(consumer: MiddlewareConsumer) {
        await this.config.merge(path.join(__dirname, '**/*.config.{ts,js}'));
    }
}

registerHelper(name: string, fn: (...args:any[]) => any): ConfigService

Register custom global helper

this.config.registerHelper('isProduction', () => {
    return this.get('express.environment') === 'production';
});

Decorators

It's possible to use decorators instead of injecting the ConfigService. But note that @Configurable() decorator replaces descriptor.value for the method with own function. Regarding to the current nestjs implementation (Issue-1180) this behavior will break all decorators that follow after Configurable() decorator.

For the right behavior @Configurable() decorator MUST be placed at the last place when you use several decorators for one method.

Working example:

import {Injectable, Get} from '@nestjs/common';
import {Configurable, ConfigParam} from 'nestjs-config';

@Injectable()
export default class UserController {
    
    @Get("/")
    @Configurable()
    index(@ConfigParam('my.parameter', 'deafult value') parameter?: string) {
        return { data: parameter };
    }
}

Broken example:

import {Injectable, Get, UseInterceptors} from '@nestjs/common';
import {Configurable, ConfigParam} from 'nestjs-config';
import {TransformInterceptor} from '../interceptors';

@Injectable()
export default class UserController {
    
    @Configurable()
    @Get("/")   // <-- nestjs decorator won't work because it placed after @Configurable()
    @UseInterceptors(TransformInterceptor)// <-- nestjs decorator won't work because it placed after @Configurable()
    index(@ConfigParam('my.parameter', 'deafult value') parameter?: string) {
        return { data: parameter };
    }
}

Broken example 2:

import {Injectable, Get, UseInterceptors} from '@nestjs/common';
import {Configurable, ConfigParam} from 'nestjs-config';
import {TransformInterceptor} from '../interceptors';

@Injectable()
export default class UserController {
    
    
    @Get("/") // <-- nestjs decorator will work fine because it placed after @Configurable()
    @Configurable()
    @UseInterceptors(TransformInterceptor) // <-- nestjs decorator won't work because it placed after @Configurable()
    index(@ConfigParam('my.parameter', 'deafult value') parameter?: string) {
        return { data: parameter };
    }
}

Typeorm

Usage with typeorm requires the use of the forRootAsync function supplied by the typeorm package for nestjs

import {Module} from '@nestjs/common';
import {ConfigModule, ConfigService} from 'nestjs-config';
import {TypeOrmModule} from '@nestjs/typeorm';
import * as path from 'path';

@Module({
    imports: [
        ConfigModule.load(path.resolve(__dirname, 'config/**/*.{ts,js}')),
        TypeOrmModule.forRootAsync({
            useFactory: (config: ConfigService) => config.get('database'),
            inject: [ConfigService],
        }),
    ],
})
export default class AppModule {}

And your config file:

//config/database.ts
export default {
    type: 'mysql',
    host: process.env.DB_HOST,
    username: process.env.DB_USERNAME,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME,
    port: parseInt(process.env.DB_PORT),
};

Built from Fenos, Shekohex and Bashleigh