All Projects โ†’ nestjsx โ†’ Nestjs Config

nestjsx / Nestjs Config

Licence: mit
Config module for nestjs using dotenv ๐Ÿ”‘

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to Nestjs Config

nest-typed-config
Intuitive, type-safe configuration module for Nest framework โœจ
Stars: โœญ 47 (-90.08%)
Mutual labels:  config, dotenv, nestjs
ini
๐Ÿ“ Go INI config management. support multi file load, data override merge. parse ENV variable, parse variable reference. Dotenv file parse and loader. INI้…็ฝฎ่ฏปๅ–็ฎก็†๏ผŒๆ”ฏๆŒๅคšๆ–‡ไปถๅŠ ่ฝฝ๏ผŒๆ•ฐๆฎ่ฆ†็›–ๅˆๅนถ, ่งฃๆžENVๅ˜้‡, ่งฃๆžๅ˜้‡ๅผ•็”จใ€‚DotEnv ่งฃๆžๅŠ ่ฝฝ
Stars: โœญ 72 (-84.81%)
Mutual labels:  config, dotenv
exenv
Exenv makes loading environment variables from external sources easy.
Stars: โœญ 35 (-92.62%)
Mutual labels:  config, dotenv
superconfig
Access environment variables. Also includes presence validation, type coercion and default values.
Stars: โœญ 33 (-93.04%)
Mutual labels:  config, dotenv
nestjs-config
NestJS Module for Nonfig services. Nonfig combines Configurations and Features. So you change features, and release swiftly, and measure to digital impact.
Stars: โœญ 40 (-91.56%)
Mutual labels:  config, nestjs
Python Dotenv
Get and set values in your .env file in local and production servers. ๐ŸŽ‰
Stars: โœญ 4,533 (+856.33%)
Mutual labels:  dotenv
Izumi
Productivity-oriented collection of lightweight fancy stuff for Scala toolchain
Stars: โœญ 423 (-10.76%)
Mutual labels:  config
Docs.nestjs.com
The official documentation https://docs.nestjs.com ๐Ÿ“•
Stars: โœญ 389 (-17.93%)
Mutual labels:  nestjs
Nestjs Typeorm Paginate
๐Ÿ“ƒ Pagination response object function + types for typeorm + nestjs
Stars: โœญ 377 (-20.46%)
Mutual labels:  nestjs
Magento Nginx Config
Default Nginx config for Magento
Stars: โœญ 462 (-2.53%)
Mutual labels:  config
Koanf
Light weight, extensible configuration management library for Go. Built in support for JSON, TOML, YAML, env, command line, file, S3 etc. Alternative to viper.
Stars: โœญ 450 (-5.06%)
Mutual labels:  config
Awesome Dotfiles
Dotfiles for awesome people using the awesomewm linux environment
Stars: โœญ 409 (-13.71%)
Mutual labels:  config
Sync Dotenv
Keep your .env in sync with .env.example
Stars: โœญ 393 (-17.09%)
Mutual labels:  dotenv
Pgsh
Branch your PostgreSQL Database like Git
Stars: โœญ 428 (-9.7%)
Mutual labels:  dotenv
Api
๐Ÿ๐Ÿ› ๏ธ SaaS backend & API framework based on @nestjs
Stars: โœญ 390 (-17.72%)
Mutual labels:  nestjs
Nestjs Bff
A full-stack TypeScript solution, and starter project. Includes an API, CLI, and example client webapp. Features include production grade logging, authorization, authentication, MongoDB migrations, and end-to-end testing.
Stars: โœญ 450 (-5.06%)
Mutual labels:  nestjs
Nest Ideas Api
REST API for app ideas built in nestjs
Stars: โœญ 380 (-19.83%)
Mutual labels:  nestjs
Conf For Surge Shadowrocket
Surge Shadowrocket conf
Stars: โœญ 405 (-14.56%)
Mutual labels:  config
Airframe
Essential Building Blocks for Scala
Stars: โœญ 442 (-6.75%)
Mutual labels:  config
Nest Router
Router Module For Nestjs Framework ๐Ÿšฆ ๐Ÿš€
Stars: โœญ 403 (-14.98%)
Mutual labels:  nestjs

travis npm license coveralls package quality dependabot PRs welcome Awesome Nest Nest Powered npm downloads

Nestjs Config

Configuration component for NestJs.

Features

  • Load your configuration files using globs
  • Support for different environment configurations, 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 src/config in our project that contains several configuration files.

/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';
import * as path from 'path';

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

That's it!


Complex Project Structure

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

We want to be able to set a different 'root path' to load our configurations from. Be it src or dist.

Imagine a more complex project structure like this:

/
โ”œโ”€โ”€ 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

In this example, config files are located in the /src/config 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, the ConfigModule is imported in the BootstrapModule, but not directly in AppModule.

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

ConfigService.rootPath = path.resolve(__dirname, '..');

@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('config', '**/!(*.d).{ts,js}')),
    ],
})
export class BootstrapModule {}

Setting the ConfigService.rootPath before calling ConfigModule.load(...) will change the default root dir of where your configs are loaded from.

Another method is to invoke ConfigModule.resolveRootPath(__dirname) from any module before loading the config and use glob with a relative path.

// bootstrap.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from 'nestjs-config';

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

In both cases we provide the glob of our configuration as first argument, but it is relative to the src/ folder (or eventually dist/).

Multi-modular config usage

In some cases your structure might take on this shape

/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ cats/
โ”‚   โ”‚   โ”œโ”€โ”€ cats.module.ts
โ”‚   โ”‚   โ””โ”€โ”€ cats.config.ts
โ”‚   โ”œโ”€โ”€ dogs/
โ”‚   โ”‚   โ”œโ”€โ”€ dogs.module.ts
โ”‚   โ”‚   โ””โ”€โ”€ dogs.config.ts
โ”‚   โ”œโ”€โ”€ app.module.ts
โ”‚   โ””โ”€โ”€ main.ts
โ”œโ”€โ”€ tsconfig.json
โ””โ”€โ”€ package.json

With the examples above you'd have to call your config like so ConfigService.get('dogs.config.bark'). You can use the modifyConfigName method option to change the name of your configs

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

@Module({
    imports: [
        ConfigModule.load(path.resolve(__dirname, '**/!(*.d).config.{ts,js}'), {
            modifyConfigName: name => name.replace('.config', ''),
        }),
    ],
})
export class AppModule {}

Now you can call your config like so ConfigService.get('dogs.bark').

Production environments

You might have notice the use of config/**/!(*.d).{ts,js} in the glob. When running in production (running in JavaScript after TypeScript compilation) we want to disinclude the TypeScript definition files. The use of config/**/*.ts is fine in dev environments but we recommend using this example config/**/!(*.d).{ts,js} to avoid issues later on when running in a production environment.

Environment Configuration

This package ships with the amazing dotenv package that allows you to create a .env file in your preferred location.

Let's create one, for demo purposes!

# .env
EXPRESS_PORT=3000

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

// src/config/express.ts
export default {
    port: process.env.EXPRESS_PORT || 3000,
}

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

Usage

Now we are ready to inject our ConfigService anywhere 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 may also use the @InjectConfig decorator as following:

import {InjectConfig} from 'nestjs-config';

@Injectable()
class SomeService {

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

Custom Helpers

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

Reconsider the isProduction() method from above. But in this case, let's define it as a helper:

// src/config/express.ts

export default {

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

You can use the helper function as follows:

// this.config is the ConfigService!
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';
});

And then use it like this:

this.config.isProduction(); // note the missing underscore prefix

Decorators

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

For the expected behavior, the @Configurable() decorator MUST be placed at the last position 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', 'default 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', 'default 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 before @Configurable()
    @Configurable()
    @UseInterceptors(TransformInterceptor) // <-- nestjs decorator won't work because it placed after @Configurable()
    index(@ConfigParam('my.parameter', 'default value') parameter?: string) {
        return { data: parameter };
    }
}

TypeORM

Using the ConfigModule in combination with TypeORM (e.g. in order to configure TypeORM) requires using the forRootAsync() function supplied by the typeorm package for nestjs (@nestjs/typeorm)

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', '**', '!(*.d).{ts,js}')),
        TypeOrmModule.forRootAsync({
            useFactory: (config: ConfigService) => config.get('database'),
            inject: [ConfigService],
        }),
    ],
})
export default class AppModule {}

Your config file may look something like this:

//config/database.ts
export default {
    type: 'mysql',
    host: process.env.TYPEORM_HOST,
    username: process.env.TYPEORM_USERNAME,
    password: process.env.TYPEORM_PASSWORD,
    database: process.env.TYPEORM_DATABASE,
    port: parseInt(process.env.TYPEORM_PORT),
    logging: process.env.TYPEORM_LOGGING === 'true',
    entities: process.env.TYPEORM_ENTITIES.split(','),
    migrationsRun: process.env.TYPEORM_MIGRATIONS_RUN === 'true',
    synchronize: process.env.TYPEORM_SYNCHRONIZE === 'true',
};

We recommend using a TYPEORM_ prefix so when running in production environments you're also able to use the same envs for running the typeorm cli. More options here

Custom env file path

You can specify dotenv options with the second parameter of the load method

ConfigModule.load(path.resolve(__dirname, '*/**!(*.d).config.{ts,js}'), {
    path: path.resolve(__dirname, '..', '.env.staging')),
});

Using different env files

Create a .env file at the root directory of your application had always been the best practice. You could also create custom .env file per different environments.

# .env
EXPRESS_PORT=3000

# .env.dev
EXPRESS_PORT=3001

# .env.testing
EXPRESS_PORT=3002

# .env.staging
EXPRESS_PORT=3003
const ENV = process.env.NODE_ENV;

ConfigModule.load(path.resolve(__dirname, '*/**!(*.d).config.{ts,js}'), {
  path: path.resolve(process.cwd(), !ENV ? '.env' : `.env.${ENV}`),
});

Perhaps you need a custom directory to manage env files.

In this example, the name of the custom directory is env.

/
โ”œโ”€โ”€ dist/
โ”œโ”€โ”€ env/
โ”‚   โ”œโ”€โ”€ .env.dev
โ”‚   โ”œโ”€โ”€ .env.testing
โ”‚   โ””โ”€โ”€ .env.staging
โ”‚   โ”‚
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ config/
โ”‚   โ”‚   โ””โ”€โ”€ typeorm.config.ts
โ”‚   โ””โ”€โ”€ main.ts
โ”œโ”€โ”€ tsconfig.json
โ””โ”€โ”€ package.json
const ENV = process.env.NODE_ENV;

ConfigModule.load(path.resolve(__dirname, '*/**!(*.d).config.{ts,js}'), {
  path: path.resolve(process.cwd(), 'env', !ENV ? '.env' : `.env.${ENV}`),
});

Note: If you place env files inside an src directory, you won't be able to see env files included as a final output in outDir since TS compiler will never transpile files that do not match with *.ts extension.

Support

Any support is welcome. At least you can give us a star โญ๏ธ

Contributors

Code Contributors

This project exists thanks to all the people who contribute. [Contribute].

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. It returns a default value if the key does not exist.

this.config.get('server.port'); // 3000
this.config.get('an.undefined.value', 'foobar'); // 'foobar' is returned if the key does not exist

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

Set a value at runtime, it creates the specified key / value if it doesn't already 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 is set.

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

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

Load other configuration files at runtime. This is great for package development.

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

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

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

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

Register a custom global helper function

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

resolveRootPath(path: string): typeof ConfigService

change the root path from where configs files are loaded

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

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

root(path: string = ''): string

Returns the current working dir or defined rootPath.

ConfigService.root(); // /var/www/src
ConfigService.root('some/path/file.html'); // /var/www/src/some/path/file.html

ConfigService.resolveRootPath(__dirname).root(); // /var/www/src/app (or wherever resolveRootPath has been called with)

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].