node-comfortv2.0.0

nc.env

Environment variables you can trust: .env loading, typed getters, and validate() to check your whole configuration at startup and report every problem at once.

The .env file in the working directory is loaded when the package is required; variables that are already set are never overwritten. Set NODE_COMFORT_DOTENV=false to turn that off.

const { env } = require("@ix-xs/node-comfort");
import { parse } from "@ix-xs/node-comfort/env";
const config = env.validate({
  PORT: { type: "port", default: 3000 },
  DATABASE_URL: { type: "url" },                  // required
  CACHE_TTL: { type: "duration", default: "5m" }, // in ms
});
config.PORT; // a number, typed in your editor
GuideExplanations and examples for nc.env.
Read the guide →

Functions

nc.env.parse()

parse(content: string, options?: EnvParseOptions): Record<string, string>

Parses the text of a .env file: quotes, multi-line values, export, comments, escapes, and ${VAR} expansion (except in single quotes).

Parameters

NameType
contentstring
optionsoptionalEnvParseOptions

Returns Record<string, string>

Example

env.parse('PORT=3000\nURL="http://localhost:${PORT}"');
// { PORT: "3000", URL: "http://localhost:3000" }

nc.env.load()

load(files?: string | string[], options?: EnvLoadOptions): Record<string, string>

Loads .env files into process.env. The first file to set a variable wins, and variables that are already set are kept, unless you pass override.

Parameters

NameTypeDescription
filesoptionalstring | string[]Relative to the working directory.Default: ".env"
optionsoptionalEnvLoadOptions

Returns Record<string, string>: Everything read from the files.

Throws Error If required is set and a file is missing.

Example

env.load();                                // ./.env
env.load([".env.local", ".env"]);          // local values win
env.load(".env.test", { override: true });

nc.env.get()

get(name: string, fallback?: string): string | undefined

Reads a variable, with a fallback. Never throws.

Parameters

NameType
namestring
fallbackoptionalstring

Returns string | undefined

Example

env.get("REGION", "eu-west-1");

nc.env.has()

has(name: string): boolean

Is the variable set, even to an empty string?

Parameters

NameType
namestring

Returns boolean

nc.env.required()

required(name: string): string

Reads a variable that must be set and not empty.

Parameters

NameType
namestring

Returns string

Throws ValidationError If it's missing or empty.

Example

const key = env.required("STRIPE_SECRET_KEY");

nc.env.string()

string(name: string, options?: (EnvGetterOptions<string> & { pattern?: RegExp; minLength?: number; }) | undefined): string

Reads a string. Required unless you give a default or optional.

Parameters

NameType
namestring
optionsoptionalEnvGetterOptions<string> & { pattern?: RegExp, minLength?: number }

Returns string

Throws ValidationError

Example

env.string("APP_NAME", { default: "my-app" });

nc.env.number()

number(name: string, options?: (EnvGetterOptions<number> & { min?: number; max?: number; integer?: boolean; }) | undefined): number

Reads a number.

Parameters

NameType
namestring
optionsoptionalEnvGetterOptions<number> & { min?: number, max?: number, integer?: boolean }

Returns number

Throws ValidationError

Example

env.number("WORKERS", { default: 4, min: 1, integer: true });

nc.env.bool()

bool(name: string, options?: EnvGetterOptions<boolean>): boolean

Reads a boolean: true/false, 1/0, yes/no or on/off.

Parameters

NameType
namestring
optionsoptionalEnvGetterOptions<boolean>

Returns boolean

Throws ValidationError

Example

if (env.bool("FEATURE_BETA", { default: false })) enableBeta();

nc.env.port()

port(name: string, options?: EnvGetterOptions<number>): number

Reads a port number.

Parameters

NameType
namestring
optionsoptionalEnvGetterOptions<number>

Returns number

Throws ValidationError

Example

server.listen(env.port("PORT", { default: 3000 }));

nc.env.url()

url(name: string, options?: (EnvGetterOptions<string> & { protocols?: string[]; }) | undefined): string

Reads an absolute URL.

Parameters

NameType
namestring
optionsoptionalEnvGetterOptions<string> & { protocols?: string[] }

Returns string

Throws ValidationError

Example

env.url("DATABASE_URL", { protocols: ["postgres", "postgresql"] });

nc.env.duration()

duration(name: string, options?: EnvGetterOptions<string | number>): number

Reads a duration like "30s" or "1h30m" and returns milliseconds.

Parameters

NameType
namestring
optionsoptionalEnvGetterOptions<number | string>

Returns number

Throws ValidationError

Example

env.duration("CACHE_TTL", { default: "10m" }); // 600000

nc.env.list()

list(name: string, options?: (EnvGetterOptions<string[]> & { separator?: string; }) | undefined): string[]

Reads a comma-separated list. Items are trimmed and empty ones dropped.

Parameters

NameType
namestring
optionsoptionalEnvGetterOptions<string[]> & { separator?: string }

Returns string[]

Throws ValidationError

Example

// ALLOWED_ORIGINS="https://a.com, https://b.com"
env.list("ALLOWED_ORIGINS", { default: [] }); // ["https://a.com", "https://b.com"]

nc.env.json()

json<T = any>(name: string, options?: EnvGetterOptions<T>): T

Reads a JSON value.

Parameters

NameType
namestring
optionsoptionalEnvGetterOptions<T>

Returns T

Throws ValidationError

Example

const flags = env.json("FEATURE_FLAGS", { default: {} });

nc.env.oneOf()

oneOf<V extends string>(name: string, values: readonly V[], options?: EnvGetterOptions<V>): V

Reads a variable that must be one of the given values. The result has their literal type.

Parameters

NameType
namestring
valuesreadonly V[]
optionsoptionalEnvGetterOptions<V>

Returns V

Throws ValidationError

Example

env.oneOf("LOG_LEVEL", ["debug", "info", "warn", "error"], { default: "info" });

nc.env.validate()

validate<T extends Record<string, EnvVarSpec>>(spec: T, options?: { env?: ProcessEnv; } | undefined): Readonly<EnvConfig<T>>

Checks all your variables at once and returns a typed, frozen config. If anything is wrong, one ValidationError lists every problem, so a bad deployment fails at startup with the full picture.

Parameters

NameType
specT
optionsoptional{ env?: NodeJS.ProcessEnv }

Returns Readonly<EnvConfig<T>>

Throws ValidationError

Example

const config = env.validate({
  NODE_ENV: { type: "enum", values: ["development", "production", "test"], default: "development" },
  PORT: { type: "port", default: 3000 },
  DATABASE_URL: { type: "url", protocols: ["postgres"] },
  JWT_SECRET: { type: "string", minLength: 32 },
  SENTRY_DSN: { type: "url", optional: true },
});
// ValidationError: Validation failed with 2 issues:
//   • DATABASE_URL: is required but is not set
//   • JWT_SECRET: must contain at least 32 characters

nc.env.mode()

mode(): string

NODE_ENV, or "development" when it's not set.

Returns string

nc.env.isProduction()

isProduction(): boolean

Is NODE_ENV set to "production"?

Returns boolean

nc.env.isDevelopment()

isDevelopment(): boolean

Is NODE_ENV "development", or not set?

Returns boolean

nc.env.isTest()

isTest(): boolean

Are we running tests? True when NODE_ENV is "test" or a test runner like node --test or Jest is detected.

Returns boolean

Types

Import any of them in TypeScript with import type { EnvConfig } from "@ix-xs/node-comfort", or in JavaScript with import("@ix-xs/node-comfort").EnvConfig.

EnvConfig

What validate() returns.

type EnvConfig = { -readonly [K in keyof T]: T[K] extends { optional: true; } ? EnvVarValue<T[K]> | undefined : EnvVarValue<T[K]>; }

EnvGetterOptions

Options shared by the typed getters.

PropertyTypeDescription
defaultoptionalTUsed when the variable is missing or empty. Without it, the variable is required.
optionaloptionalbooleanReturn undefined instead of throwing when it's missing.
envoptionalProcessEnvWhere to read from. Defaults to process.env.

EnvLoadOptions

Options for load().

PropertyTypeDescription
overrideoptionalbooleanOverwrite variables that are already set.
expandoptionalbooleanReplace ${OTHER} references. Defaults to true.
requiredoptionalbooleanThrow if a file is missing.
targetoptionalProcessEnvWhere to put the variables. Defaults to process.env.

EnvParseOptions

Options for parse().

PropertyTypeDescription
expandoptionalbooleanReplace $VAR, ${VAR} and ${VAR:-default}. Defaults to true.
envoptionalRecord<string, string | undefined>Other variables usable in expansions. Defaults to process.env.

EnvVarSpec

One variable in validate(). It's required unless it has a default or optional: true.

type EnvVarSpec = ({ type: "string"; default?: string; optional?: boolean; pattern?: RegExp; minLength?: number; description?: string; } | { type: "number"; default?: number; optional?: boolean; min?: number; max?: number; integer?: boolean; description?: string; } | { type: "boolean"; default?: boolean; optional?: boolean; description?: string; } | { type: "port"; default?: number; optional?: boolean; description?: string; } | { type: "url"; default?: string; optional?: boolean; protocols?: string[]; description?: string; } | { type: "email"; default?: string; optional?: boolean; description?: string; } | { type: "duration"; default?: number | string; optional?: boolean; description?: string; } | { type: "list"; default?: string[]; optional?: boolean; separator?: string; description?: string; } | { type: "json"; default?: unknown; optional?: boolean; description?: string; } | { type: "enum"; values: readonly string[]; default?: string; optional?: boolean; description?: string; })

EnvVarValue

The type a variable gets once read.

type EnvVarValue = S["type"] extends "number" | "port" | "duration" ? number : S["type"] extends "boolean" ? boolean : S["type"] extends "list" ? string[] : S["type"] extends "json" ? any : S extends { values: readonly (infer V)[]; } ? V : string
node-comfort v2.0.0View the source