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 editornc.env.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
| Name | Type |
|---|---|
content | string |
optionsoptional | EnvParseOptions |
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
| Name | Type | Description |
|---|---|---|
filesoptional | string | string[] | Relative to the working directory.Default: ".env" |
optionsoptional | EnvLoadOptions |
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 | undefinedReads a variable, with a fallback. Never throws.
Parameters
| Name | Type |
|---|---|
name | string |
fallbackoptional | string |
Returns string | undefined
Example
env.get("REGION", "eu-west-1");nc.env.has()
has(name: string): booleanIs the variable set, even to an empty string?
Parameters
| Name | Type |
|---|---|
name | string |
Returns boolean
nc.env.required()
required(name: string): stringReads a variable that must be set and not empty.
Parameters
| Name | Type |
|---|---|
name | string |
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): stringReads a string. Required unless you give a default or optional.
Parameters
| Name | Type |
|---|---|
name | string |
optionsoptional | EnvGetterOptions<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): numberReads a number.
Parameters
| Name | Type |
|---|---|
name | string |
optionsoptional | EnvGetterOptions<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>): booleanReads a boolean: true/false, 1/0, yes/no or on/off.
Parameters
| Name | Type |
|---|---|
name | string |
optionsoptional | EnvGetterOptions<boolean> |
Returns boolean
Throws ValidationError
Example
if (env.bool("FEATURE_BETA", { default: false })) enableBeta();nc.env.port()
port(name: string, options?: EnvGetterOptions<number>): numberReads a port number.
Parameters
| Name | Type |
|---|---|
name | string |
optionsoptional | EnvGetterOptions<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): stringReads an absolute URL.
Parameters
| Name | Type |
|---|---|
name | string |
optionsoptional | EnvGetterOptions<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>): numberReads a duration like "30s" or "1h30m" and returns milliseconds.
Parameters
| Name | Type |
|---|---|
name | string |
optionsoptional | EnvGetterOptions<number | string> |
Returns number
Throws ValidationError
Example
env.duration("CACHE_TTL", { default: "10m" }); // 600000nc.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
| Name | Type |
|---|---|
name | string |
optionsoptional | EnvGetterOptions<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>): TReads a JSON value.
Parameters
| Name | Type |
|---|---|
name | string |
optionsoptional | EnvGetterOptions<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>): VReads a variable that must be one of the given values. The result has their literal type.
Parameters
| Name | Type |
|---|---|
name | string |
values | readonly V[] |
optionsoptional | EnvGetterOptions<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
| Name | Type |
|---|---|
spec | T |
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 charactersnc.env.mode()
mode(): stringNODE_ENV, or "development" when it's not set.
Returns string
nc.env.isProduction()
isProduction(): booleanIs NODE_ENV set to "production"?
Returns boolean
nc.env.isDevelopment()
isDevelopment(): booleanIs NODE_ENV "development", or not set?
Returns boolean
nc.env.isTest()
isTest(): booleanAre 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.
| Property | Type | Description |
|---|---|---|
defaultoptional | T | Used when the variable is missing or empty. Without it, the variable is required. |
optionaloptional | boolean | Return undefined instead of throwing when it's missing. |
envoptional | ProcessEnv | Where to read from. Defaults to process.env. |
EnvLoadOptions
Options for load().
| Property | Type | Description |
|---|---|---|
overrideoptional | boolean | Overwrite variables that are already set. |
expandoptional | boolean | Replace ${OTHER} references. Defaults to true. |
requiredoptional | boolean | Throw if a file is missing. |
targetoptional | ProcessEnv | Where to put the variables. Defaults to process.env. |
EnvParseOptions
Options for parse().
| Property | Type | Description |
|---|---|---|
expandoptional | boolean | Replace $VAR, ${VAR} and ${VAR:-default}. Defaults to true. |
envoptional | Record<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