{"id":14978645,"url":"https://github.com/nikaple/nest-typed-config","last_synced_at":"2025-05-15T04:03:48.705Z","repository":{"id":42660200,"uuid":"365221590","full_name":"Nikaple/nest-typed-config","owner":"Nikaple","description":"Intuitive, type-safe configuration module for Nest framework ✨","archived":false,"fork":false,"pushed_at":"2025-04-02T19:01:06.000Z","size":1830,"stargazers_count":214,"open_issues_count":16,"forks_count":27,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-06T23:11:55.549Z","etag":null,"topics":["config","configuration","configuration-management","dotenv","javascript","nest","nestjs","strongly-typed","type","type-safety","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Nikaple.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-05-07T12:10:04.000Z","updated_at":"2025-03-24T14:26:38.000Z","dependencies_parsed_at":"2024-03-18T20:00:41.490Z","dependency_job_id":"861b7bb3-586c-4ea4-a645-edff5ba65020","html_url":"https://github.com/Nikaple/nest-typed-config","commit_stats":{"total_commits":545,"total_committers":21,"mean_commits":"25.952380952380953","dds":0.4715596330275229,"last_synced_commit":"4cecec0338d44e0bc500ad0f80f99b76181dd68d"},"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nikaple%2Fnest-typed-config","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nikaple%2Fnest-typed-config/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nikaple%2Fnest-typed-config/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nikaple%2Fnest-typed-config/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Nikaple","download_url":"https://codeload.github.com/Nikaple/nest-typed-config/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248819381,"owners_count":21166477,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["config","configuration","configuration-management","dotenv","javascript","nest","nestjs","strongly-typed","type","type-safety","typescript"],"created_at":"2024-09-24T13:58:06.936Z","updated_at":"2025-04-14T03:59:12.489Z","avatar_url":"https://github.com/Nikaple.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eNest-Typed-Config\u003c/h1\u003e\n\n\u003ch3 align=\"center\"\u003eNever write strings to read config again.\u003c/h3\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://www.npmjs.com/package/nest-typed-config\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/nest-typed-config.svg\" alt=\"NPM Version\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://www.npmjs.com/package/nest-typed-config\"\u003e\u003cimg src=\"https://img.shields.io/npm/l/nest-typed-config.svg\" alt=\"Package License\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://www.npmjs.com/package/nest-typed-config\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/nest-typed-config.svg\" alt=\"NPM Downloads\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/Nikaple/nest-typed-config/actions/workflows/build.yml\"\u003e\u003cimg src=\"https://github.com/Nikaple/nest-typed-config/workflows/build/badge.svg\" alt=\"build\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://coveralls.io/github/Nikaple/nest-typed-config?branch=main\"\u003e\u003cimg src=\"https://coveralls.io/repos/github/Nikaple/nest-typed-config/badge.svg?branch=main\" alt=\"Coverage\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Features\n\n- Provide a type-safe and intuitive way to config your [Nest](https://github.com/nestjs/nest) projects, just as smooth as request DTO.\n- Load your configuration with environment variables, json/yaml/toml configuration files or remote endpoints.\n- Validate your configuration with [class-validator](https://github.com/typestack/class-validator) and [class-transformer](https://github.com/typestack/class-transformer).\n- Provide easy to use options by default, meanwhile everything is customizable.\n\n## Installation\n\n```bash\n$ npm i --save nest-typed-config\n```\n\n`Nest-typed-config` will install the dependencies for all loaders by default. If you care about dependency size and bootstrap time, please checkout [the guide to skip optional dependencies](./OPTIONAL-DEP.md).\n\n## Inspiration\n\nThere are various popular configuration modules for [Nest framework](https://github.com/nestjs/nest), such as the [official configuration module](https://github.com/nestjs/config), [nestjs-config](https://github.com/nestjsx/nestjs-config) and [nestjs-easyconfig](https://github.com/rubiin/nestjs-easyconfig). These modules can help to manage configurations, validate them, and load them through the `ConfigService`. But that's when type-safety is gone. For example:\n\n```ts\n// @nestjs/config, with type-casting\nconst dbUser = this.configService.get\u003cstring\u003e('DATABASE_USER');\n// nestjs-config, returns `any` type\nconst env = this.config.get('app.environment');\n// nestjs-easyconfig, only string is supported\nconst value = this.config.get('key');\n```\n\nWriting type casting is a pain and hard to maintain, and it's common to use non-string configurations in real-world projects. This module aims to provide an intuitive and type-safe way to load, validate and use configurations. Just import any config model, and inject it with full TypeScript support. In a nutshell:\n\n```ts\n// config.ts\nexport class Config {\n  @IsString()\n  public readonly host!: string;\n\n  @IsNumber()\n  public readonly port!: number;\n}\n\n// app.service.ts\nimport { Config } from './config';\n\n@Injectable()\nexport class AppService {\n  constructor(private readonly config: Config) {}\n\n  show() {\n    console.log(`http://${this.config.host}:${this.config.port}`);\n  }\n}\n```\n\n## Quick Start\n\nLet's define the configuration model first. It can be nested at arbitrary depth.\n\n```ts\n// config.ts\nimport { Allow, ValidateNested } from 'class-validator';\n\n// validator is omitted for simplicity\nexport class TableConfig {\n  @Allow()\n  public readonly name!: string;\n}\n\nexport class DatabaseConfig {\n  @Type(() =\u003e TableConfig)\n  @ValidateNested()\n  public readonly table!: TableConfig;\n}\n\nexport class RootConfig {\n  @Type(() =\u003e DatabaseConfig)\n  @ValidateNested()\n  public readonly database!: DatabaseConfig;\n}\n```\n\nThen, add a configuration file such as `.env.yaml` under project root directory:\n\n```yaml\ndatabase:\n  table:\n    name: example\n```\n\nAfter creating the configuration file, import `TypedConfigModule` and `fileLoader` to load configuration from file system.\n\n```ts\n// app.module.ts\nimport { Module } from '@nestjs/common';\nimport { TypedConfigModule, fileLoader } from 'nest-typed-config';\nimport { AppController } from './app.controller';\nimport { AppService } from './app.service';\nimport { RootConfig } from './config';\n\n// Register TypedConfigModule\n@Module({\n  imports: [\n    TypedConfigModule.forRoot({\n      schema: RootConfig,\n      load: fileLoader(),\n    }),\n  ],\n  providers: [AppService],\n  controllers: [AppController],\n})\nexport class AppModule {}\n```\n\nThat's it! You can use any config or sub-config you defined as injectable services now!\n\n```ts\n// app.service.ts\nimport { Injectable } from '@nestjs/common';\nimport { RootConfig, DatabaseConfig, TableConfig } from './config';\n\n@Injectable()\nexport class AppService {\n  // inject any config or sub-config you like\n  constructor(\n    private config: RootConfig,\n    private databaseConfig: DatabaseConfig,\n    private tableConfig: TableConfig,\n  ) {}\n\n  // enjoy type safety!\n  public show(): any {\n    const out = [\n      `root.name: ${this.config.name}`,\n      `root.database.name: ${this.databaseConfig.name}`,\n      `root.database.table.name: ${this.tableConfig.name}`,\n    ].join('\\n');\n\n    return `${out}\\n`;\n  }\n}\n```\n\nFor a full example, please visit [CodeSandbox](https://codesandbox.io/s/affectionate-tdd-1juv6?file=/src/config.ts), or our [examples](https://github.com/Nikaple/nest-typed-config/blob/main/examples/basic/src/app.module.ts) folder.\n\n## Using loaders\n\n### Using dotenv loader\n\nThe `dotenvLoader` function allows you to load configuration with [dotenv](https://github.com/motdotla/dotenv), which is similar to the [official configuration module](https://github.com/nestjs/config). You can use this loader to load configuration from `.env` files or environment variables.\n\n#### Example\n\n```ts\nTypedConfigModule.forRoot({\n  schema: RootConfig,\n  load: dotenvLoader({\n    /* options */\n  }),\n});\n```\n\n#### Passing options\n\nThe `dotenvLoader` function optionally expects a `DotenvLoaderOptions` object as a first parameter:\n\n````ts\nexport interface DotenvLoaderOptions {\n  /**\n   * If set, use the separator to parse environment variables to objects.\n   *\n   * @example\n   *\n   * ```bash\n   * app__port=8080\n   * db__host=127.0.0.1\n   * db__port=3000\n   * ```\n   *\n   * if `separator` is set to `__`, environment variables above will be parsed as:\n   *\n   * ```json\n   * {\n   *     \"app\": {\n   *         \"port\": 8080\n   *     },\n   *     \"db\": {\n   *         \"host\": \"127.0.0.1\",\n   *         \"port\": 3000\n   *     }\n   * }\n   * ```\n   */\n  separator?: string;\n\n  /**\n   * If set, this function will transform all environment variable keys prior to parsing.\n   *\n   * Be aware: If you transform multiple keys to the same value only one will remain!\n   *\n   * @example\n   *\n   * .env file: `PORT=8080` and `keyTransformer: key =\u003e key.toLowerCase()` results in `{\"port\": 8080}`\n   *\n   * @param key environment variable key\n   */\n  keyTransformer?: (key: string) =\u003e string;\n\n  /**\n   * If \"true\", environment files (`.env`) will be ignored.\n   */\n  ignoreEnvFile?: boolean;\n\n  /**\n   * If \"true\", predefined environment variables will not be validated.\n   */\n  ignoreEnvVars?: boolean;\n\n  /**\n   * Path to the environment file(s) to be loaded.\n   */\n  envFilePath?: string | string[];\n\n  /**\n   * A boolean value indicating the use of expanded variables.\n   * If .env contains expanded variables, they'll only be parsed if\n   * this property is set to true.\n   *\n   * Internally, dotenv-expand is used to expand variables.\n   */\n  expandVariables?: boolean;\n}\n````\n\n### Using file loader\n\nThe `fileLoader` function allows you to load configuration with [cosmiconfig](https://github.com/davidtheclark/cosmiconfig). You can use this loader to load configuration from files with various extensions, such as `.json`, `.yaml`, `.toml` or `.js`.\n\nBy default, `fileLoader` searches for `.env.{ext}` (ext = json, yaml, toml, js) configuration file starting at `process.cwd()`, and continues to search up the directory tree until it finds some acceptable configuration (or hits the home directory). Moreover, configuration of current environment takes precedence over general configuration (`.env.development.toml` is loaded instead of `.env.toml` when `NODE_ENV=development`)\n\n#### Example\n\n```ts\nTypedConfigModule.forRoot({\n  schema: RootConfig,\n  load: fileLoader({\n    /* options */\n  }),\n});\n```\n\n#### Passing options\n\nThe `fileLoader` function optionally expects a `FileLoaderOptions` object as a first parameter:\n\n```ts\nimport { OptionsSync } from 'cosmiconfig';\n\nexport interface FileLoaderOptions extends Partial\u003cOptionsSync\u003e {\n  /**\n   * basename of config file, defaults to `.env`.\n   *\n   * In other words, `.env.yaml`, `.env.yml`, `.env.json`, `.env.toml`, `.env.js`\n   * will be searched by default.\n   */\n  basename?: string;\n  /**\n   * Use given file directly, instead of recursively searching in directory tree.\n   */\n  absolutePath?: string;\n  /**\n   * The directory to search from, defaults to `process.cwd()`. See: https://github.com/davidtheclark/cosmiconfig#explorersearch\n   */\n  searchFrom?: string;\n  /**\n   * If \"true\", ignore environment variable substitution.\n   * Default: true\n   */\n  ignoreEnvironmentVariableSubstitution?: boolean;\n}\n```\n\nIf you want to add support for other extensions, you can use [`loaders`](https://github.com/davidtheclark/cosmiconfig#loaders) property provided by `cosmiconfig`:\n\n```ts\nTypedConfigModule.forRoot({\n  schema: RootConfig,\n  load: fileLoader({\n    // .env.ini has the highest priority now\n    loaders: {\n      '.ini': iniLoader,\n    },\n  }),\n});\n```\n\n### Using directory loader\n\nThe `directoryLoader` function allows you to load configuration within a given directory.\n\nThe basename of files will be interpreted as config namespace, for example:\n\n```\n.\n└─config\n    ├── app.toml\n    └── db.toml\n\n// app.toml\nfoo = 1\n\n// db.toml\nbar = 1\n```\n\nThe folder above will generate configuration as follows:\n\n```json\n{\n  \"app\": {\n    \"foo\": 1\n  },\n  \"db\": {\n    \"bar\": 1\n  }\n}\n```\n\n#### Example\n\n```ts\nTypedConfigModule.forRoot({\n  schema: RootConfig,\n  load: directoryLoader({\n    directory: '/absolute/path/to/config/directory',\n    /* other cosmiconfig options */\n  }),\n});\n```\n\n#### Passing options\n\nThe `directoryLoader` function optionally expects a `DirectoryLoaderOptions` object as a first parameter:\n\n```ts\nimport { OptionsSync } from 'cosmiconfig';\n\nexport interface DirectoryLoaderOptions extends OptionsSync {\n  /**\n   * The directory containing all configuration files.\n   */\n  directory: string;\n  /**\n   * File regex to include.\n   */\n  include?: RegExp;\n  /**\n   * If \"true\", ignore environment variable substitution.\n   * Default: true\n   */\n  ignoreEnvironmentVariableSubstitution?: boolean;\n  /**\n   * If \"true\", disallow undefined environment variables.\n   * Default: true\n   */\n  disallowUndefinedEnvironmentVariables?: boolean;\n}\n```\n\nIf you want to add support for other extensions, you can use [`loaders`](https://github.com/davidtheclark/cosmiconfig#loaders) property provided by `cosmiconfig`:\n\n```ts\nTypedConfigModule.forRoot({\n  schema: RootConfig,\n  load: directoryLoader({\n    directory: '/path/to/configuration',\n    // .env.ini has the highest priority now\n    loaders: {\n      '.ini': iniLoader,\n    },\n  }),\n});\n```\n\n### Using remote loader\n\nThe `remoteLoader` function allows you to load configuration from a remote endpoint, such as configuration center. Internally [@nestjs/axios](https://github.com/nestjs/axios) is used to perform http requests.\n\n#### Example\n\n```ts\n// forRootAsync should be used when loading configuration asynchronously\nTypedConfigModule.forRootAsync({\n  schema: RootConfig,\n  load: remoteLoader('http://localhost:8080', {\n    /* options */\n  }),\n});\n```\n\n#### Passing options\n\nThe `remoteLoader` function optionally expects a `RemoteLoaderOptions` object as a second parameter, which accepts all `axios` request configuration except `url`.\n\n```ts\nexport interface RemoteLoaderOptions extends AxiosRequestConfigWithoutUrl {\n  /**\n   * Config file type\n   */\n  type?: ((response: any) =\u003e RemoteLoaderConfigType) | RemoteLoaderConfigType;\n\n  /**\n   * A function that maps http response body to corresponding config object\n   */\n  mapResponse?: (config: any) =\u003e Promise\u003cany\u003e | any;\n\n  /**\n   * A function that determines if the request should be retried\n   */\n  shouldRetry?: (response: AxiosResponse) =\u003e boolean;\n\n  /**\n   * Number of retries to perform, defaults to 3\n   */\n  retries?: number;\n\n  /**\n   * Interval in milliseconds between each retry\n   */\n  retryInterval?: number;\n}\n```\n\nYou can use the `mapResponse` function to preprocess the server response before parsing with `type`, and use `shouldRetry` function to determine whether server response is valid or not. When server response is not valid, you can use `retries` and `retryInterval` to adjust retry strategies. For example:\n\n```ts\n/*\n  Example server response:\n  {\n    \"code\": 0,\n    \"fileName\": \".env.yaml\",\n    \"fileType\": \"yaml\",\n    \"fileContent\": \"database:\\n    table:\\n        name: example\"\n  }\n*/\n\nTypedConfigModule.forRootAsync({\n    schema: RootConfig,\n    load: remoteLoader('http://localhost:8080', {\n        type: response =\u003e response.fileType,\n        mapResponse: response =\u003e response.fileContent\n        // retry when http status is not 200, or response code is not zero\n        shouldRetry: response =\u003e response.data.code !== 0\n        retries: 3,\n        retryInterval: 3000\n    }),\n})\n```\n\n### Using multiple loaders\n\nLoading configuration from file system is convenient for development, but when it comes to deployment, you may need to load configuration from environment variables, especially in a dockerized environment. This can be easily achieved by providing multiple loaders. For example:\n\n```ts\nTypedConfigModule.forRoot({\n  schema: RootConfig,\n  // Loaders having larger index take precedence over smaller ones,\n  // make sure dotenvLoader comes after fileLoader ensures that\n  // environment variables always have the highest priority\n  load: [\n    fileLoader({\n      /* options */\n    }),\n    dotenvLoader({\n      /* options */\n    }),\n  ],\n});\n```\n\n### Using custom loader\n\nIf native loaders provided by `nest-typed-config` can't meet your needs, you can implement a custom loader. This can be achieved by providing a function which returns the configuration object synchronously or asynchronously through the `load` option. For example:\n\n```ts\nTypedConfigModule.forRootAsync({\n  schema: RootConfig,\n  load: async () =\u003e {\n    return {\n      host: '127.0.0.1',\n      port: 3000,\n    };\n  },\n});\n```\n\n## Uses of variable substitutions\n\nThe `${PORT}` substitution feature lets you use environment variable in some nice ways. You can also provide default values, and reference another variable in a config\n\nIf you have config file with like the below one\n\n```yaml\ndatabase:\n  host: 127.0.0.1\n  port: ${PORT:-12345}\n  url: ${database.host}:${database:port}\n```\n\nAnd you have set environment variable for port\n\n```bash\nPORT=9000\n```\n\nAnd set ignoreEnvironmentVariableSubstitution to false in the FileLoaderOptions\n\n```\nload: fileLoader({\n  ignoreEnvironmentVariableSubstitution: false,\n}),\n```\n\nthen `fileloader` will resolve `${PORT}` placeholder and replace with environment variable.\nAnd you will get new config like below one\n\n```yaml\ndatabase:\n  host: 127.0.0.1\n  port: 9000\n  url: 127.0.0.1:9000\n```\n\nif you won't set environment variable for port, then you will get new config like below one\n\n```yaml\ndatabase:\n  host: 127.0.0.1\n  port: 12345\n  url: 127.0.0.1:12345\n```\n\n\u003e [!NOTE]\n\u003e when you use variable substitution the values can be string in case if you use default variable or env variable, and you need to apply transformer to class fields to get the correct type of the value.\n\n```ts\nexport class Config {\n  @IsString()\n  public readonly host!: string;\n\n  @IsNumber()\n  @Type(() =\u003e Number)\n  public readonly port!: number;\n\n  @IsString()\n  public readonly url!: string;\n}\n```\n\n## Default values\n\nJust define your default values in config schema, and you are ready to go:\n\n```ts\n// config.ts\nexport class Config {\n  @IsString()\n  public readonly host: string = '127.0.0.1';\n\n  @IsNumber()\n  public readonly port: number = 3000;\n}\n```\n\n## Transforming the raw configuration\n\nEnvironment variables are always loaded as strings, but configuration schemas are not. In such case, you can transform the raw config with `normalize` function:\n\n```ts\n// config.ts\nexport class Config {\n  @IsString()\n  public readonly host: string;\n\n  @IsNumber()\n  public readonly port: number;\n}\n\n// app.module.ts\nTypedConfigModule.forRoot({\n  schema: RootConfig,\n  load: dotenvLoader(),\n  normalize(config) {\n    config.port = parseInt(config.port, 10);\n    return config;\n  },\n});\n```\n\n## Custom getters\n\nYou can define custom getters on config schema to extract common logic:\n\n```ts\nexport class Config {\n  @IsString()\n  public readonly host: string = '127.0.0.1';\n\n  @IsNumber()\n  public readonly port: number = 3000;\n\n  @IsString()\n  public get url(): string {\n    return `http://${this.host}:${this.port}`;\n  }\n}\n```\n\n## Multiple Schemas\n\nJust call `TypedConfigModule.forRoot` multiple times, and you're ready to go!\n\n\u003e PS: Please do not share any class or sub-class between schemas, or Nest.js won't know which class to inject.\n\n```ts\n// config.ts\nexport class FooConfig {\n  @IsString()\n  foo!: string;\n}\nexport class BazConfig {\n  @IsString()\n  baz!: string;\n}\n\n// app.module.ts\n@Module({\n  imports: [\n    // load FooConfig from config file\n    TypedConfigModule.forRoot({\n      schema: FooConfig,\n      load: fileLoader(),\n    }),\n    // load BazConfig from environment variables\n    TypedConfigModule.forRoot({\n      schema: BazConfig,\n      load: dotenvLoader(),\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n## Custom validate function\n\nIf the default `validate` function doesn't suite your use case, you can provide it like in the example below:\n\n```ts\nTypedConfigModule.forRoot({\n  schema: RootConfig,\n  validate: (rawConfig: any) =\u003e {\n    const config = plainToClass(RootConfig, rawConfig);\n    const schemaErrors = validateSync(config, {\n      forbidUnknownValues: true,\n      whitelist: true,\n    });\n\n    if (schemaErrors.length) {\n      throw new Error(TypedConfigModule.getConfigErrorMessage(schemaErrors));\n    }\n\n    return config as RootConfig;\n  },\n});\n```\n\n## Using config outside Nest's IoC container (Usage in decorators)\n\n### Caution!\n\nUsing config outside Nest's IoC container will:\n\n1. make you struggle harder writing unit tests.\n2. force you to register `TypedConfigModule` synchronously using `forRoot`, since asynchronous configuration loading doesn't make sense under this situation.\n\n### How to\n\nDue to the nature of JavaScript loading modules, decorators are executed before Nest's module initialization. If you want to get config value in decorators like `@Controller()` or `@WebSocketGateway()`, config module should be initialized before application bootstrap.\n\nSuppose we need to inject routing information from the configuration, then we can define the configuration like this:\n\n```ts\n// config.ts\nimport { Type } from 'class-transformer';\nimport { ValidateNested, IsString } from 'class-validator';\n\nexport class RouteConfig {\n  @IsString()\n  public readonly app!: string;\n}\n\nexport class RootConfig {\n  @ValidateNested()\n  @Type(() =\u003e RouteConfig)\n  public readonly route!: RouteConfig;\n}\n```\n\nThen create a configuration file:\n\n```yaml\nroute:\n  app: /app\n```\n\nAfter creating the configuration file, we can initialize our `ConfigModule` with `TypedConfigModule`, and select `RootConfig` from `ConfigModule` using `selectConfig` method.\n\n```ts\n// config.module.ts\nimport { TypedConfigModule, fileLoader, selectConfig } from 'nest-typed-config';\nimport { RouteConfig } from './config';\n\nexport const ConfigModule = TypedConfigModule.forRoot({\n  schema: RootConfig,\n  load: fileLoader(),\n});\n\nexport const rootConfig = selectConfig(ConfigModule, RootConfig);\nexport const routeConfig = selectConfig(ConfigModule, RouteConfig);\n```\n\nThat's it! You can use `rootConfig` and `routeConfig` anywhere in your app now!\n\n\u003e If target configuration model is marked with `@Optional()`, you should call `selectConfig` with `{ allowOptional: true }` to allow optional configuration.\n\n```ts\n// app.controller.ts\nimport { Controller, Get } from '@nestjs/common';\nimport { AppService } from './app.service';\nimport { rootConfig } from './config.module';\n\n@Controller(routeConfig.app)\nexport class AppController {\n  constructor(private readonly appService: AppService) {}\n\n  @Get()\n  show(): void {\n    return this.appService.show();\n  }\n}\n```\n\nFor a full example, please visit [CodeSandbox](https://codesandbox.io/s/restless-snowflake-l2eyx?file=/src/config.module.ts), or our [examples](https://github1s.com/Nikaple/nest-typed-config/blob/main/examples/preload/src/app.module.ts) folder.\n\n## API\n\nPlease refer to our [API website](https://nikaple.github.io/nest-typed-config) for full documentation.\n\n## Changelog\n\nPlease refer to [changelog.md](https://github.com/Nikaple/nest-typed-config/blob/main/changelog.md)\n\n## License\n\n[MIT](LICENSE).\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=Nikaple/nest-typed-config\u0026type=Date)](https://star-history.com/#Nikaple/nest-typed-config\u0026Date)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikaple%2Fnest-typed-config","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnikaple%2Fnest-typed-config","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikaple%2Fnest-typed-config/lists"}