{"id":24773037,"url":"https://github.com/re-quant/typed-node-env","last_synced_at":"2026-05-06T05:34:20.735Z","repository":{"id":57170170,"uuid":"282759447","full_name":"Re-Quant/typed-node-env","owner":"Re-Quant","description":"💥 Strictly typed access and type-casting for ENV variables 👏","archived":false,"fork":false,"pushed_at":"2020-08-20T14:19:48.000Z","size":759,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-12-19T17:07:50.620Z","etag":null,"topics":["config","configuration","configuration-management","decorator","decorators","env","environment","environment-variables","nestjs","settings","ts","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Re-Quant.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-07-27T00:45:05.000Z","updated_at":"2020-08-20T14:19:48.000Z","dependencies_parsed_at":"2022-08-27T13:11:38.843Z","dependency_job_id":null,"html_url":"https://github.com/Re-Quant/typed-node-env","commit_stats":null,"previous_names":["z-brain/typed-node-env"],"tags_count":6,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Re-Quant%2Ftyped-node-env","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Re-Quant%2Ftyped-node-env/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Re-Quant%2Ftyped-node-env/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Re-Quant%2Ftyped-node-env/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Re-Quant","download_url":"https://codeload.github.com/Re-Quant/typed-node-env/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245168905,"owners_count":20571804,"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","decorator","decorators","env","environment","environment-variables","nestjs","settings","ts","typescript"],"created_at":"2025-01-29T04:35:28.872Z","updated_at":"2026-05-06T05:34:20.696Z","avatar_url":"https://github.com/Re-Quant.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Typed Node ENV\n\n\u003cp align=\"center\"\u003e\n  \u003ca target=\"_blank\" href=\"https://www.gnu.org/licenses/gpl-3.0\"\u003e\n    \u003cimg alt=\"License: GPL v3\" src=\"https://img.shields.io/badge/License-GPLv3-blue.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca target=\"_blank\" href=\"https://www.npmjs.com/package/@z-brain/typed-node-env\"\u003e\n    \u003cimg alt=\"NPM version\" src=\"https://img.shields.io/npm/v/@z-brain/typed-node-env.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca target=\"_blank\" href=\"https://www.npmjs.com/package/@z-brain/typed-node-env\"\u003e\n    \u003cimg alt=\"NPM Bundle size\" src=\"https://img.shields.io/bundlephobia/min/@z-brain/typed-node-env\"\u003e\n  \u003c/a\u003e\n  \u003ca target=\"_blank\" href=\"https://snyk.io/test/npm/typed-node-env\"\u003e\n    \u003cimg alt=\"Snyk Vulnerabilities for npm package\" src=\"https://img.shields.io/snyk/vulnerabilities/npm/@z-brain/typed-node-env.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca target=\"_blank\" href=\"https://github.com/z-brain/typed-node-env/actions?query=workflow%3A%22Build%22\"\u003e\n    \u003cimg alt=\"Build status\" src=\"https://github.com/z-brain/typed-node-env/workflows/Build/badge.svg\"\u003e\n  \u003c/a\u003e\n  \u003ca target=\"_blank\" href=\"https://codecov.io/gh/z-brain/typed-node-env\"\u003e\n    \u003cimg alt=\"Code Coverage\" src=\"https://codecov.io/gh/z-brain/typed-node-env/branch/master/graph/badge.svg\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e🧨 \u0026nbsp;\u0026nbsp; 💥 \u0026nbsp;\u0026nbsp; 💪 \u0026nbsp;\u0026nbsp; \u003cstrong\u003eStrictly typed access and type-casting for ENV variables\u003c/strong\u003e \u0026nbsp;\u0026nbsp; ✅ \u0026nbsp;\u0026nbsp; 👨‍💻 \u0026nbsp;\u0026nbsp; 😎\u003c/p\u003e\n\n\u003cp\u003e\u0026nbsp;\u003c/p\u003e\n\u003cp\u003e\u003ci\u003eNotice: If you have any propositions feel free to make an issue or create a pull request.\u003c/i\u003e\u003c/p\u003e\n\n## :package: Installation\n\n`yarn add @z-brain/typed-node-env`  \nor  \n`npm i -s @z-brain/typed-node-env`\n\n## :running: Get started\n\nCreate a config class with decorated properties `config.ts`\n\n```typescript\nimport { EnvString, EnvInteger, EnvBoolean, Environment } from '@z-brain/typed-node-env';\n\n@Environment()\nexport class EnvConfig {\n  @EnvString()\n  public readonly host!: string;\n\n  @EnvInteger()\n  public readonly port!: number;\n\n  @EnvBoolean()\n  public readonly production!: boolean;\n}\n\nconst config = new EnvConfig();\n\nconsole.log(\n  config.host === 'test.net',\n  config.port === 3000,\n  config.production === false,\n);\n```\n\nDue to the used decorators, the values for all properties can now be set via environment variables:\n\n```sh\nHOST=test.net PORT=3000 PRODUCTION=false ts-node config.ts\n```\n\n## :tada: Benefits\n\n- Type safety for your configuration:\n  - No need to maintain a separate TypeScript interface\n  - Types can be infered from the property's default value\n  - Enforce correct types for values passed by environment variables and notifies about errors\n  - Type-casting. For example fields with `boolean` type are correctly recognized from the well-known stringified values: `'true'/'false'/'1'/'0'`\n  - Automatically handles any kind of array types\n- Take advantage of having a configuration class:\n  - Calculate config values based on other config values (e.g. `url` from `host` and `port`)\n  - Getter functions (e.g. `get debugPort() { return this.port + 1000; }`)\n  - Inherit from other configuration classes\n- Enforce configuration values to be read-only at compile time ([readonly modifier](https://www.typescriptlang.org/docs/handbook/classes.html#readonly-modifier)) and at runtime (`enforceReadonly` option)\n- Load environment variables from a local file (using [dotenv](https://www.npmjs.com/package/dotenv/v/6.2.0))\n\n## :warning: Human-readable error messages\n\n* A required ENV variable is absent:  \n  `NoEnvVarError: Variable \"BASE_URL\" is required for AppConfig.baseUrl`\n* ENV variable value can't be casted to the specified type:   \n  ```\n  TypeCastingError: AppConfig.debug: Boolean-like value expected, something else is gotten.\n      Raw Value (string): \"000\"\n      Env Var Name: \"DEBUG\"\n      Is Array: false\n  ```\n* Int expected, a float has been gotten:  \n  ```\n  AppConfig.logLevel: An Integer number expected, a Float is gotten.\n      Raw Value (string): \"11.1\"\n      Env Var Name: \"LOG_LEVEL\"\n      Is Array: false\n  ```\n * Int array expected, one item of array is a string:   \n   ```\n   TypeCastingError: Config.adminUserIDs: An Integer number expected, NaN is gotten.\n       Raw Value (string): \"11,22,abc,33\"\n       Env Var Name: \"ADMIN_USER_IDS\"\n       Is Array: true\n   ```\n\n## :books: Documentation\n\n### All decorators\n\n* Type Casting property decorators\n    * `@EnvInteger()`\n    * `@EnvFloat()`\n    * `@EnvString()`\n    * `@EnvBoolean()`\n    * `@EnvEnum()`\n* Other\n    * `@EnvNested()` To create nested configuration objects\n    * `@Environment()` Wraps class and makes `.loadEnvConfig()` call during instantiating\n\n### Class property name \u0026 ENV variable name\n\nUsually we write class properties in `camelCase` notation and environment variable names in `SCREAMING_SNAKE_CASE` notation. How can we relate them?\n1. In a simple case `typed-node-env` package does internal transformation of class property name from came-case to ENV variable name in screaming-snake-case.\n2. You can specify custom ENV name for a field.\n   ```typescirpt\n     @EnvInteger('APP_PORT')\n     public port!: number;\n   ```\n3. It is possible to specify multiple ENV names for the same property.  \n   In this case `typed-node-env` tries to find a first existing ENV variable in the order in which the names listed.\n   @EnvInteger(['PORT', 'APP_PORT', 'HTTP_PORT'])\n   public port!: number;\n4. In case of nested object configured using `@EnvNested()` decorator\n   1. By default, names of the property that contains a nested object is concatenated to each property name of the nested object.\n      ```typescript\n      class DbConfig {\n        @EnvString()\n        public host!: string; // \u003c--- DB_HOST\n      \n        @EnvInteger('PWD')\n        public password!: string; // \u003c--- DB_PWD (custom name is prefixed too)\n      }\n      \n      class Config {\n        @EnvNested()\n        public db!: DbConfig;\n      }\n      ```\n   2. Also, you can customize prefix name `@EnvNested('MY_PREFIX')`\n5. It even possible to use the same config class for different fields to make complex nested object.\n   ```typescript\n   class DbInsConfig {\n     @EnvString()\n     public host!: string;\n     @EnvString()\n     public login!: string;\n     @EnvString()\n     public password!: string;\n   }\n   class DbConfig {\n     @EnvNested()\n     master!: DbInsConfig;\n     @EnvNested()\n     slave!: DbInsConfig;\n   }\n   @Environment()\n   class Config {\n     @EnvNested()\n     public db!: DbConfig;\n   }\n   const env = new Config();\n   ```\n   This config is looking for next variables:\n   ```\n   DB_MASTER_HOST      # ---\u003e env.db.master.host\n   DB_MASTER_LOGIN     # ---\u003e env.db.master.login\n   DB_MASTER_PASSWORD  # ---\u003e env.db.master.password\n   DB_SLAVE_HOST       # ---\u003e env.db.slave.host\n   DB_SLAVE_LOGIN      # ---\u003e env.db.slave.login\n   DB_SLAVE_PASSWORD   # ---\u003e env.db.slave.password\n   ```\n\n### Instantiating\n\n1. The classic way is using `new` keyword.  \n   To use this way the config class should be decorated with `@Environment()` decorator.  \n   Notice: Internally during the instantiating of the class `Environment` decorator uses `loadEnvConfig` function under the hood.\n   ```typescript\n   @Environment\n   class EnvConfig {\n     // ...\n   }\n   const env = new EnvConfig();\n   ```\n2. Manual `loadEnvConfig()` function call.  \n   It can be helpful if by some reasons you don't have to instantiate the config manually using `new` keyword.\n   `loadEnvConfig` function works with both class constructors and with instances.\n   ```typescript\n   // No @Environment() decorator here\n   class EnvConfig {\n     // ...\n   }\n   // env1 is a filled instance of EnvConfig\n   const env1 = loadEnvConfig(EnvConfig);\n   \n   const env2Empty = new EnvConfig(); // totally empty object without any fields\n   const env2 = loadEnvConfig(env2Empty);\n   expect(env2Empty).toBe(env2);\n\n   expect(env2).toEqual(env1); // all fields are equal\n   ```\n\n### `.allowEmpty` flag\n\n1. The default behavior is throwing an error about absent ENV variable in case the value of the variable is an empty string or a string filled only with spaces.\n2. If we are decorate fields with any of `@Env*({ allowEmpty: true })` decorators such \"empty\" values will be consumed and passed to type casting function.  \n   Here is a table of values to which such values will be converted by different decorators:  \n   \n   | decorator | input value | result |\n   | --- | --- | --- |\n   | `EnvBoolean` | `'   '` or `''` | `false` |\n   | `EnvFloat` | `'   '` or `''` | `0` |\n   | `EnvInteger` | `'   '` or `''` | `0` |\n   | `EnvString` | `'   '` | `'   '` |\n   | `EnvString` | `''` | `''` |\n   | `EnvEnum` | `''` | throws error except cases when an empty\u003cbr\u003estring is a enum option value |\n   | `EnvEnum` | `'  '` | throws error except cases when `'   '` string\u003cbr\u003eis a enum option value |\n\n### Handling arrays\n\nTyped Node Env automatically detects array type and splits input ENV variables data by commas (`,`).\n\n```\nenum ETest {\n  One  = 'one',\n  Two  = 'two',\n  Three = 'three',\n}\n@Environment()\nclass EnvConfig {\n  @EnvString()\n  public hosts!: string[]        // [ 'my.com', 'your.net' ]\n\n  @EnvInteger()\n  public ports!: number[]        // [ 80, 8080 ]\n\n  @EnvFloat()\n  public percentages!: number[]  // [ 0.75, 2.3 ]\n\n  @EnvBoolean()\n  public mask!: boolean[]        // [ false, false, true, false ]\n\n  @EnvEnum(ETest)\n  public testEnum!: ETest[]      // [ 'One', 'Two' ]\n}\nconst env = new EnvConfig();\n```\n\nENV variables\n```bash\nHOSTS=my.com,your.net\nPORTS=80,8080\nPERCENTAGES=0.75,2.3\nMASK=false,false,true,false\nTEST_ENUM=One,Two\n```\n\n### Mixed types\n\nYou can define any mixed types for your properties and use multiple `@Env*()` decorators for the same property.\n\nUse case for TypeORM .logging field handling\n```typescript\n/** This is a complex type from TypeORM */\ntype LoggerOptions = boolean | 'all' | ('query' | 'schema' | 'error' | 'warn' | 'info' | 'log' | 'migration')[];\n\nconst allowedValues: LoggerOptions = ['query', 'schema', 'error', 'warn', 'info', 'log', 'migration'];\nclass EnvConfig {\n    @EnvBoolean()\n    @EnvEnum({ enum: allowedValues, isArray: true })\n    @EnvEnum({ enum: ['all'] })\n    public logging!: LoggerOptions;\n}\n```\n\nVarious of the ENV variable value:\n```shell script\nLOGGING=true             # in TS will be transformed to true\nLOGGING=all              # in TS will be transformed to 'all'\nLOGGING=error,warn,info  # in TS will be transformed to ['error', 'warn', 'info']\n```\n\n### More examples\n\nYou can find a lot of examples in the [typed-env-integration.spec.ts](src/typed-env-integration.spec.ts)\n\n### Similar projects\n\n* https://github.com/igabesz/config-decorators\n* https://github.com/jbpionnier/env-decorator\n* https://github.com/Hippocrate/env-decorator\n* https://github.com/derbenoo/ts-configurable\n\n## :wrench: Development notes\n\n### Quick Start\n\n```bash\ncd /code/z-brain\ngit clone git@github.com:z-brain/typed-node-env.git\ncd typed-node-env\nyarn install\n```\n\n### How to use NodeJS version from the `.nvmrc`\n\n1. Install NVM\n2. Use `.nvmrc` file one of the next ways:\n\n    * Execute `nvm use` in the project root directory\n    * Install [NVM Loader](https://github.com/korniychuk/ankor-shell) and your .nvmrc will be loaded automatically when you open the terminal.\n      ![NVM Loader demo](./resources/readme.nvm-loader.png)\n\n### How to make a build\n\n`npm run build`\n\n### How to run lint\n\n* Just show problems `npm run lint`\n* Fix problems if it is possible `npm run lint:fix`\n\n### How to run tests\n\n* All tests\n\n  `npm run test`  \n  `npm run test:watch`\n* Specific tests\n\n  `npm run test -- src/my.spec.ts`  \n  `npm run test:watch -- src/my.spec.ts`\n\n### How to build and publish NPM package\n\n*NPM Token:* `6cf9...7ab8`\n\nCI configuration details are here: [.github/workflows/npmpublish.yml](.github/workflows/npmpublish.yml)\n\n```bash\nnpm run pre-push\n\u0026\u0026 npm version patch -m 'Update package version version to %s'\n\u0026\u0026 npm run gen-public-package.json\n\u0026\u0026 cp README.md dist/\n\u0026\u0026 npm publish dist --access public\n\u0026\u0026 git push --no-verify \u0026\u0026 git push --tags --no-verify\n```\n\n### How to build a package for local installation\n\n1. `yarn run build:local`\n2. Then you can install a local package build from path `file:.../typed-node-env/dist`.\n\n## :man_technologist: Author\n\n| [\u003cimg src=\"https://www.korniychuk.pro/avatar.jpg\" width=\"100px;\"/\u003e\u003cbr /\u003e\u003csub\u003eAnton Korniychuk\u003c/sub\u003e](https://korniychuk.pro) |\n| :---: |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fre-quant%2Ftyped-node-env","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fre-quant%2Ftyped-node-env","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fre-quant%2Ftyped-node-env/lists"}