UNPKG

9.88 kBMarkdownView Raw
1<p align="center">
2 <img
3 src="https://raw.githubusercontent.com/af/envalid/main/.github/logo.svg"
4 width="160"
5 alt="Envalid text logo with drop shadow"
6 />
7</p>
8
9<p align="center">
10 <strong>
11 Envalid is a small library for validating and accessing<br />
12 environment variables in Node.js programs
13 </strong>
14</p>
15
16<p align="center">
17 <a href="https://github.com/af/envalid/actions/workflows/ci.yml">
18 <img src="https://github.com/af/envalid/workflows/continuous-integration/badge.svg" alt="Current GitHub Build Status Badge" />
19 </a>
20</p>
21
22Envalid is a small library for validating and accessing environment variables in
23Node.js programs, aiming to:
24
25- Ensure that your program only runs when all of its environment dependencies are met
26- Give you executable documentation about the environment your program expects to run in
27- Give you an immutable API for your environment variables, so they don't change
28 from under you while the program is running
29
30## Why Envalid?
31
32- Type-safe: written completely in TypeScript, with great support for inference
33- Light: no dependencies besides [tslib](https://github.com/Microsoft/tslib)
34- Modular: customize behavior with custom validators, middleware, and reporters
35
36## API
37
38### `envalid.cleanEnv(environment, validators, options)`
39
40`cleanEnv()` returns a sanitized, immutable environment object, and accepts three
41positional arguments:
42
43- `environment` - An object containing your env vars (eg. `process.env`)
44- `validators` - An object that specifies the format of required vars.
45- `options` - An (optional) object, which supports the following key:
46 - `reporter` - Pass in a function to override the default error handling and
47 console output. See `src/reporter.ts` for the default implementation.
48
49By default, `cleanEnv()` will log an error message and exit (in Node) or throw (in browser) if any required
50env vars are missing or invalid. You can override this behavior by writing your own reporter.
51
52```js
53import { cleanEnv, str, email, json } from 'envalid'
54
55const env = cleanEnv(process.env, {
56 API_KEY: str(),
57 ADMIN_EMAIL: email({ default: 'admin@example.com' }),
58 EMAIL_CONFIG_JSON: json({ desc: 'Additional email parameters' }),
59 NODE_ENV: str({ choices: ['development', 'test', 'production', 'staging'] }),
60})
61
62// Read an environment variable, which is validated and cleaned during
63// and/or filtering that you specified with cleanEnv().
64env.ADMIN_EMAIL // -> 'admin@example.com'
65
66// Envalid checks for NODE_ENV automatically, and provides the following
67// shortcut (boolean) properties for checking its value:
68env.isProduction // true if NODE_ENV === 'production'
69env.isTest // true if NODE_ENV === 'test'
70env.isDev // true if NODE_ENV === 'development'
71```
72
73For an example you can play with, clone this repo and see the `example/` directory.
74
75```
76git clone https://github.com/af/envalid
77cd envalid
78yarn prepare
79node example/server.js
80```
81
82## Validator types
83
84Node's `process.env` only stores strings, but sometimes you want to retrieve other types
85(booleans, numbers), or validate that an env var is in a specific format (JSON,
86URL, email address). To these ends, the following validation functions are available:
87
88- `str()` - Passes string values through, will ensure a value is present unless a
89 `default` value is given. Note that an empty string is considered a valid value -
90 if this is undesirable you can easily create your own validator (see below)
91- `bool()` - Parses env var strings `"1", "0", "true", "false", "t", "f"` into booleans
92- `num()` - Parses an env var (eg. `"42", "0.23", "1e5"`) into a Number
93- `email()` - Ensures an env var is an email address
94- `host()` - Ensures an env var is either a domain name or an ip address (v4 or v6)
95- `port()` - Ensures an env var is a TCP port (1-65535)
96- `url()` - Ensures an env var is a URL with a protocol and hostname
97- `json()` - Parses an env var with `JSON.parse`
98
99Each validation function accepts an (optional) object with the following attributes:
100
101- `choices` - An Array that lists the admissible parsed values for the env var.
102- `default` - A fallback value, which will be present in the output if the env var wasn't specified.
103 Providing a default effectively makes the env var optional. Note that `default`
104 values are not passed through validation logic, they are default _output_ values.
105- `devDefault` - A fallback value to use _only_ when `NODE_ENV` is explicitly set and _not_ `'production'`.
106 This is handy for env vars that are required for production environments, but optional
107 for development and testing.
108- `desc` - A string that describes the env var.
109- `example` - An example value for the env var.
110- `docs` - A URL that leads to more detailed documentation about the env var.
111
112## Custom validators
113
114### Basic usage
115
116You can easily create your own validator functions with `envalid.makeValidator()`. It takes
117a function as its only parameter, and should either return a cleaned value, or throw if the
118input is unacceptable:
119
120```js
121import { makeValidator, cleanEnv } from 'envalid'
122const twochars = makeValidator((x) => {
123 if (/^[A-Za-z]{2}$/.test(x)) return x.toUpperCase()
124 else throw new Error('Expected two letters')
125})
126
127const env = cleanEnv(process.env, {
128 INITIALS: twochars(),
129})
130```
131
132### TypeScript users
133
134You can use either one of `makeValidator`, `makeExactValidator` and `makeStructuredValidator`
135depending on your use case.
136
137#### `makeValidator<BaseT>`
138
139This validator has the output narrowed down to a subtype of `BaseT` (e.g. `str`).
140Example of a custom integer validator:
141
142```ts
143const int = makeValidator<number>((input: string) => {
144 const coerced = parseInt(input, 10)
145 if (Number.isNaN(coerced)) throw new EnvError(`Invalid integer input: "${input}"`)
146 return coerced
147})
148const MAX_RETRIES = int({ choices: [1, 2, 3, 4] })
149// Narrows down output type to '1 | 2 | 3 | 4' which is a subtype of 'number'
150```
151
152#### `makeExactValidator<T>`
153
154This validator has the output widened to `T` (e.g. `bool`). To understand the difference
155with `makeValidator`, let's use it in the same scenario:
156
157```ts
158const int = makeExactValidator<number>((input: string) => {
159 const coerced = parseInt(input, 10)
160 if (Number.isNaN(coerced)) throw new EnvError(`Invalid integer input: "${input}"`)
161 return coerced
162})
163const MAX_RETRIES = int({ choices: [1, 2, 3, 4] })
164// Output type is 'number'
165```
166
167As you can see in this instance, _the output type is exactly `number`, the parameter type of
168`makeExactValidator`_. Also note that here, `int` is not parametrizable.
169
170## Error Reporting
171
172By default, if any required environment variables are missing or have invalid
173values, Envalid will log a message and call `process.exit(1)`. You can override
174this behavior by passing in your own function as `options.reporter`. For example:
175
176```js
177const env = cleanEnv(process.env, myValidators, {
178 reporter: ({ errors, env }) => {
179 emailSiteAdmins('Invalid env vars: ' + Object.keys(errors))
180 },
181})
182```
183
184Additionally, Envalid exposes `EnvError` and `EnvMissingError`, which can be checked in case specific error handling is desired:
185
186```js
187const env = cleanEnv(process.env, myValidators, {
188 reporter: ({ errors, env }) => {
189 for (const [envVar, err] of Object.entries(errors)) {
190 if (err instanceof envalid.EnvError) {
191 ...
192 } else if (err instanceof envalid.EnvMissingError) {
193 ...
194 } else {
195 ...
196 }
197 }
198 }
199})
200```
201
202## Custom Middleware (advanced)
203
204In addition to `cleanEnv()`, as of v7 there is a new `customCleanEnv()` function,
205which allows you to completely replace the processing that Envalid applies after applying
206validations. You can use this custom escape hatch to transform the output however you wish.
207
208### `envalid.customCleanEnv(environment, validators, applyMiddleware, options)`
209
210`customCleanEnv()` uses the same API as `cleanEnv()`, but with an additional `applyMiddleware`
211argument required in the third position:
212
213- `applyMiddleware` - A function that can modify the env object after it's
214 validated and cleaned. Envalid ships (and exports) its own default
215 middleware (see src/middleware.ts), which you can mix and match with your own
216 custom logic to get the behavior you desire.
217
218## Utils
219
220### testOnly
221
222The `testOnly` helper function is available for setting a default value for an env var only when `NODE_ENV=test`. It is recommended to use this function along with `devDefault`. For example:
223
224```js
225const env = cleanEnv(process.env, {
226 SOME_VAR: envalid.str({ devDefault: testOnly('myTestValue') }),
227})
228```
229
230For more context see [this issue](https://github.com/af/envalid/issues/32).
231
232## FAQ
233
234### Can I call `structuredClone()` on Envalid's validated output?
235
236Since by default Envalid's output is wrapped in a Proxy, structuredClone [will not work](https://bugzilla.mozilla.org/show_bug.cgi?id=1269327#c1) on it. See [#177](https://github.com/af/envalid/issues/177).
237
238## Related projects
239
240- [dotenv](https://www.npmjs.com/package/dotenv) is a very handy tool for loading env vars from
241 `.env` files. It was previously used as a dependency of Envalid. To use them together, simply
242 call `require('dotenv').config()` before you pass `process.env` to your `envalid.cleanEnv()`.
243
244- [react-native-config](https://www.npmjs.com/package/react-native-config) can be useful for React Native projects for reading env vars from a `.env` file
245
246- [fastify-envalid](https://github.com/alemagio/fastify-envalid) is a wrapper for using Envalid within [Fastify](https://www.fastify.io/)
247
248- [nestjs-envalid](https://github.com/simenandre/nestjs-envalid) is a wrapper for using Envalid with [NestJS](https://nestjs.com/)
249
250- [nuxt-envalid](https://github.com/manuelhenke/nuxt-envalid) is a wrapper for using Envalid with [NuxtJS](https://nuxtjs.org/)
251
252## Motivation
253
254http://www.12factor.net/config