Home

Awesome

<p align="center"> <img src="https://raw.githubusercontent.com/af/envalid/main/.github/logo.svg" width="160" alt="Envalid text logo with drop shadow" /> </p> <p align="center"> <strong> Envalid is a small library for validating and accessing<br /> environment variables in Node.js programs </strong> </p> <p align="center"> <a href="https://github.com/af/envalid/actions/workflows/ci.yml"> <img src="https://github.com/af/envalid/workflows/continuous-integration/badge.svg" alt="Current GitHub Build Status Badge" /> </a> </p>

Envalid is a small library for validating and accessing environment variables in Node.js programs, aiming to:

Why Envalid?

API

envalid.cleanEnv(environment, validators, options)

cleanEnv() returns a sanitized, immutable environment object, and accepts three positional arguments:

By default, cleanEnv() will log an error message and exit (in Node) or throw (in browser) if any required env vars are missing or invalid. You can override this behavior by writing your own reporter.

import { cleanEnv, str, email, json } from 'envalid'

const env = cleanEnv(process.env, {
  API_KEY: str(),
  ADMIN_EMAIL: email({ default: 'admin@example.com' }),
  EMAIL_CONFIG_JSON: json({ desc: 'Additional email parameters' }),
  NODE_ENV: str({ choices: ['development', 'test', 'production', 'staging'] }),
})

// Read an environment variable, which is validated and cleaned during
// and/or filtering that you specified with cleanEnv().
env.ADMIN_EMAIL // -> 'admin@example.com'

// Envalid checks for NODE_ENV automatically, and provides the following
// shortcut (boolean) properties for checking its value:
env.isProduction // true if NODE_ENV === 'production'
env.isTest // true if NODE_ENV === 'test'
env.isDev // true if NODE_ENV === 'development'

For an example you can play with, clone this repo and see the example/ directory.

git clone https://github.com/af/envalid
cd envalid
yarn prepare
node example/server.js

Validator types

Node's process.env only stores strings, but sometimes you want to retrieve other types (booleans, numbers), or validate that an env var is in a specific format (JSON, URL, email address). To these ends, the following validation functions are available:

Each validation function accepts an (optional) object with the following attributes:

Custom validators

Basic usage

You can easily create your own validator functions with envalid.makeValidator(). It takes a function as its only parameter, and should either return a cleaned value, or throw if the input is unacceptable:

import { makeValidator, cleanEnv } from 'envalid'
const twochars = makeValidator((x) => {
  if (/^[A-Za-z]{2}$/.test(x)) return x.toUpperCase()
  else throw new Error('Expected two letters')
})

const env = cleanEnv(process.env, {
  INITIALS: twochars(),
})

TypeScript users

You can use either one of makeValidator, makeExactValidator and makeStructuredValidator depending on your use case.

makeValidator<BaseT>

This validator has the output narrowed down to a subtype of BaseT (e.g. str). Example of a custom integer validator:

const int = makeValidator<number>((input: string) => {
  const coerced = parseInt(input, 10)
  if (Number.isNaN(coerced)) throw new EnvError(`Invalid integer input: "${input}"`)
  return coerced
})
const MAX_RETRIES = int({ choices: [1, 2, 3, 4] })
// Narrows down output type to '1 | 2 | 3 | 4' which is a subtype of 'number'

makeExactValidator<T>

This validator has the output widened to T (e.g. bool). To understand the difference with makeValidator, let's use it in the same scenario:

const int = makeExactValidator<number>((input: string) => {
  const coerced = parseInt(input, 10)
  if (Number.isNaN(coerced)) throw new EnvError(`Invalid integer input: "${input}"`)
  return coerced
})
const MAX_RETRIES = int({ choices: [1, 2, 3, 4] })
// Output type is 'number'

As you can see in this instance, the output type is exactly number, the parameter type of makeExactValidator. Also note that here, int is not parametrizable.

Error Reporting

By default, if any required environment variables are missing or have invalid values, Envalid will log a message and call process.exit(1). You can override this behavior by passing in your own function as options.reporter. For example:

const env = cleanEnv(process.env, myValidators, {
  reporter: ({ errors, env }) => {
    emailSiteAdmins('Invalid env vars: ' + Object.keys(errors))
  },
})

Additionally, Envalid exposes EnvError and EnvMissingError, which can be checked in case specific error handling is desired:

const env = cleanEnv(process.env, myValidators, {
    reporter: ({ errors, env }) => {
        for (const [envVar, err] of Object.entries(errors)) {
            if (err instanceof envalid.EnvError) {
                ...
            } else if (err instanceof envalid.EnvMissingError) {
                ...
            } else {
                ...
            }
        }
    }
})

Custom Middleware (advanced)

In addition to cleanEnv(), as of v7 there is a new customCleanEnv() function, which allows you to completely replace the processing that Envalid applies after applying validations. You can use this custom escape hatch to transform the output however you wish.

envalid.customCleanEnv(environment, validators, applyMiddleware, options)

customCleanEnv() uses the same API as cleanEnv(), but with an additional applyMiddleware argument required in the third position:

Utils

testOnly

The 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:

const env = cleanEnv(process.env, {
  SOME_VAR: envalid.str({ devDefault: testOnly('myTestValue') }),
})

For more context see this issue.

FAQ

Can I call structuredClone() on Envalid's validated output?

Since by default Envalid's output is wrapped in a Proxy, structuredClone will not work on it. See #177.

Related projects

Motivation

http://www.12factor.net/config