Libraries
    Preparing search index...

    Module @cleverbrush/env

    @cleverbrush/env

    CI License: BSD-3-Clause

    Type-safe environment variable parsing with @cleverbrush/schema — validated, coerced, structured configs from process.env.

    The problem: Environment variables are untyped strings. Most apps access them via process.env.SOME_VAR! — no validation, no coercion, no structure. Missing variables surface as runtime crashes. Secrets accidentally leak into frontend bundles. Config objects are ad-hoc and fragile.

    The solution: @cleverbrush/env uses @cleverbrush/schema builders for validation and coercion, and a branded env() wrapper for type-safe variable binding. TypeScript enforces at compile time that every config leaf is bound to an environment variable. At runtime, all variables are validated at once and coerced to the correct types — with clear error messages for CI and startup logs.

    What makes it different:

    • Compile-time enforcement — forgetting env() on a config leaf is a TypeScript error, not a runtime surprise
    • Structured configs — nest objects arbitrarily deep; env vars map to leaf fields
    • Validation & coercion — full @cleverbrush/schema power: .minLength(), .coerce(), .default(), custom validators
    • Array supportsplitBy(',') preprocessor for comma-separated values
    • Clear error reporting — lists all missing and invalid vars at once with paths and types
    • Computed values — derive values from resolved config via a type-safe callback
    • Flat modeparseEnvFlat() for simple apps where keys = env var names
    Feature @cleverbrush/env t3-env envalid
    Compile-time leaf enforcement
    Nested config structures
    Schema-based validation ~
    Type coercion (number, boolean, date) Manual
    Array support
    Computed / derived values
    All-at-once error reporting
    No Zod dependency
    npm install @cleverbrush/env @cleverbrush/schema
    

    Peer dependency: @cleverbrush/schema must be installed separately.

    import { env, parseEnv, splitBy } from '@cleverbrush/env';
    import { string, number, boolean, array } from '@cleverbrush/schema';

    const config = parseEnv({
    db: {
    host: env('DB_HOST', string().default('localhost')),
    port: env('DB_PORT', number().coerce().default(5432)),
    name: env('DB_NAME', string()),
    },
    jwt: {
    secret: env('JWT_SECRET', string().minLength(32)),
    },
    debug: env('DEBUG', boolean().coerce().default(false)),
    allowedOrigins: env(
    'ALLOWED_ORIGINS',
    array(string()).addPreprocessor(splitBy(','), { mutates: false })
    ),
    });

    // Type is fully inferred:
    // {
    // db: { host: string, port: number, name: string },
    // jwt: { secret: string },
    // debug: boolean,
    // allowedOrigins: string[]
    // }

    For simple apps where each key is both the property name and the env var name:

    import { parseEnvFlat } from '@cleverbrush/env';
    import { string, number } from '@cleverbrush/schema';

    const config = parseEnvFlat({
    DB_HOST: string().default('localhost'),
    DB_PORT: number().coerce().default(5432),
    JWT_SECRET: string().minLength(32),
    });
    // Type: { DB_HOST: string, DB_PORT: number, JWT_SECRET: string }

    Forgetting env() is a compile-time error:

    parseEnv({
    db: {
    host: string(), // ← TypeScript ERROR: not assignable to EnvConfigNode
    },
    });

    Use the splitBy() preprocessor helper:

    // Comma-separated strings
    env('ALLOWED_ORIGINS', array(string()).addPreprocessor(splitBy(','), { mutates: false }))
    // "a, b, c" → ['a', 'b', 'c']

    // Comma-separated numbers
    env('PORTS', array(number().coerce()).addPreprocessor(splitBy(','), { mutates: false }))
    // "3000, 4000" → [3000, 4000]

    When variables are missing or invalid, EnvValidationError is thrown with a formatted message:

    Missing environment variables:
    - DB_NAME (required by db.name) [string]
    - JWT_SECRET (required by jwt.secret) [string]
    Invalid environment variables:
    - DB_PORT: "abc" (required by db.port) — number expected

    The error also exposes structured .missing and .invalid properties for programmatic access.

    By default, parseEnv() reads from process.env. Pass a custom source for testing or alternative runtimes:

    const config = parseEnv(schema, {
    DB_HOST: 'test-host',
    DB_PORT: '9999',
    });

    Derive values from the resolved config by passing a compute callback as the second argument. The callback receives the fully typed base config and returns an object that is deep-merged into the result:

    import { env, parseEnv } from '@cleverbrush/env';
    import { string, number } from '@cleverbrush/schema';

    const config = parseEnv(
    {
    db: {
    host: env('DB_HOST', string().default('localhost')),
    port: env('DB_PORT', number().coerce().default(5432)),
    name: env('DB_NAME', string()),
    },
    },
    (base) => ({
    db: {
    connectionString: `postgres://${base.db.host}:${base.db.port}/${base.db.name}`,
    },
    })
    );

    // base is fully typed: { db: { host: string, port: number, name: string } }
    // Result type is deep-merged:
    // { db: { host: string, port: number, name: string, connectionString: string } }

    config.db.connectionString // "postgres://localhost:5432/mydb"

    When using a compute callback, the optional source is passed as the third argument:

    const config = parseEnv(
    { host: env('HOST', string()) },
    (base) => ({ url: `http://${base.host}` }),
    { HOST: 'example.com' } // custom source
    );
    Export Type Description
    env(varName, schema) Function Binds a schema to an env var name. Required for every leaf in parseEnv().
    parseEnv(config, source?) Function Parses env vars into a validated, typed nested config object.
    parseEnv(config, compute, source?) Function Parses env vars, then deep-merges computed values from the callback.
    parseEnvFlat(schemas, source?) Function Flat convenience — keys are env var names, no env() needed.
    splitBy(separator) Function Preprocessor that splits a string into an array.
    EnvValidationError Class Thrown when env vars are missing or invalid. Has .missing and .invalid.
    EnvField<T> Type Branded wrapper type created by env().
    EnvConfig Type Config descriptor tree type (input to parseEnv).
    InferEnvConfig<T> Type Infers the runtime type from a config descriptor.

    BSD-3-Clause

    Classes

    EnvValidationError

    Interfaces

    InvalidEnvVar
    MissingEnvVar

    Type Aliases

    EnvConfig
    EnvConfigNode
    EnvField
    InferEnvConfig

    Functions

    env
    parseEnv
    parseEnvFlat
    splitBy