v8.1.0

Envapter

Read environment variables as typed values with Envapter's static and instance methods, ordered fallbacks, and fail-fast checks.

Envapter is the functional entry point to envapt. Every reader comes two ways: a static method for one-off reads, and an instance method for when you hold a new Envapter() or extend it. Both read from the same parsed cache.

import {  } from 'envapt';

// static, for a one-off read
const port = .('PORT', 3000);
const port: number
// instance, when you hold a reference const = new (); const apiUrl = .('API_URL', 'http://localhost');
const apiUrl: string

Primitives

Five readers cover the primitive types. Each parses the raw string and returns the matching type.

const  = .('APP_NAME', 'envapt'); // string
const  = .('PORT', 3000); // number
const  = .('DEBUG', false); // boolean
const  = .('MAX_UPLOAD_BYTES', 0n); // bigint
const  = .('KEY', .('envapt:key')); // symbol

getBoolean reads 1, yes, true, on as true and 0, no, false, off as false, case-insensitively. Anything else uses the fallback.

Fallbacks shape the return type

A fallback supplies the default value and removes undefined from the return type. With a fallback the return is T; without one it's T | undefined, so the type makes you handle the missing case.

const withFallback = .('API_URL', 'http://localhost');
const withFallback: string
const noFallback = .('API_URL');
const noFallback: string | undefined

Ordered keys

Any reader accepts an ordered list of keys instead of a single name. The first key with a present value wins, so an aliased or renamed variable falls back to its old name in one read. An empty value, or a whitespace-only value under strict, is skipped like an unset key.

// READONLY_URL if set, else DATABASE_URL, else the fallback
const db = .(['READONLY_URL', 'DATABASE_URL'], 'sqlite://memory');
const db: string
WARNING

Pass the array inline. A pre-declared const keys = [...] widens to string[], which does not satisfy the ordered-key tuple type.

Raw values

getRaw returns the string exactly as loaded, with no type conversion. It exists only as an instance method:

const raw = new ().('DATABASE_URL');
const raw: string | undefined

Converters

For shapes beyond primitives, two readers take a converter:

  • getUsing(key, token, fallback?) for built-in converter tokens (arrays, URLs, dates, durations, and more).
  • getWith(key, fn, fallback?) for your own (raw, fallback) => T function.
const origins = .('CORS', .({ : . }));
const origins: string[] | undefined
const retries = .('RETRIES', (, ) => ( ? () : ), 3);
const retries: unknown

Fallbacks behave like the primitives, removing undefined from the return type. The Converters page covers every built-in token.

Template strings

resolve is a tagged template that inlines env values by key, and expands any ${VAR} references inside the resolved values.

// PGUSER=app, PGPASSWORD=secret, PGHOST=db.internal, PGDATABASE=myapp
const dsn = .`postgres://${'PGUSER'}:${'PGPASSWORD'}@${'PGHOST'}/${'PGDATABASE'}`;
const dsn: string

See Templates for ${VAR} interpolation and cycle protection.

Fail-fast on missing values

require asserts that one or more keys are present and non-empty after template resolution, throwing an EnvaptError that names every missing key. A whitespace-only value counts as missing only under strict mode.

// Assuring all three keys are present at the start of the program, for example
.('DATABASE_URL', 'API_KEY', 'SENTRY_DSN');

has returns boolean with the same missing semantics as getRequired. An ordered key list falls through to the first present key. It returns true exactly when a required read of the same key would find a value.

if (!.('SENTRY_DSN')) {
    throw new ('Set SENTRY_DSN in your .env before deploying.');
}

For a typed fail-fast that returns the parsed value, use getRequired:

const url = .('DATABASE_URL', .);
const url: URL

getRequiredAll reads a whole group in one call and returns a typed record, throwing once with every missing key. A spec value is a token, an array() token, or a custom parser, and an optional casing ('camelCase', 'PascalCase', or 'kebab-case') renames the keys. Casing splits on underscores, so it expects the conventional SCREAMING_SNAKE env-var names:

const  = .(
    {
        : .,
        : .,
        : () => new (.(','))
    },
    'camelCase'
);

config;
const config: {
    databaseUrl: URL;
    port: number;
    featureFlags: Set<string>;
}

They throw on a missing value instead of returning a fallback. See Strict mode for the global switch and how required reads relate to it.

DANGER

require, getRequired, and getRequiredAll throw EnvaptError for a missing or empty key (or, under strict mode, a whitespace-only one). require and getRequiredAll collect every missing key into one error.

Best to call require and getRequiredAll at startup, not lazily inside a request path, so a missing value fails the boot rather than a live request.

Static vs instance

Statics suit scattered, one-off reads. Create an instance to carry an env reader as a dependency, or extend Envapter to group related config on one class.

class  extends  {
    readonly  = this.('PORT', 3000);
    readonly  = this.('DEBUG', false);
}

Static and instance reads hit the same cache.

Environment detection

Envapter also detects the current runtime environment and exposes it through the isProduction / isStaging / isDevelopment / isTest helpers. On Node, Bun, and Deno it auto-loads the matching .env files for that environment. The helpers, the Environment enum, and per-environment file selection are documented on Environment.

On this page