# @suaveplan/env - Type-safe environment variable loading: schema-first validation, field types, dotenv loader, presets, structured errors. ## Summary Type-safe, schema-first environment variable loading for Node.js and edge runtimes. Define a schema of typed field builders, point it at your sources, and receive a frozen record with TypeScript types inferred at compile time — no manual type annotations required. ## Documentation tree - [create-env](./src/core/create-env/create-env.md) — _(no submodules)_ - [create-env](./src/core/create-env/create-env.md) — _(no submodules)_ - [field](./src/core/field/field.md) — _(no submodules)_ - [field](./src/core/field/field.md) — _(no submodules)_ - [validator](./src/core/validator/validator.md) — _(no submodules)_ - [validator](./src/core/validator/validator.md) — _(no submodules)_ - [env-error](./src/errors/env-error.md) — Provides the complete error class hierarchy and a value-object factory for `@suaveplan/env`. All classes extend `Suavep… - [error-codes](./src/errors/error-codes.md) — Defines and registers all stable error codes for the `@suaveplan/env` package using the `defineCodes` factory from `@su… - [array-field](./src/fields/array-field/array-field.md) — _(no submodules)_ - [array-field](./src/fields/array-field/array-field.md) — _(no submodules)_ - [boolean-field](./src/fields/boolean-field/boolean-field.md) — _(no submodules)_ - [boolean-field](./src/fields/boolean-field/boolean-field.md) — _(no submodules)_ - [email-field](./src/fields/email-field/email-field.md) — _(no submodules)_ - [email-field](./src/fields/email-field/email-field.md) — _(no submodules)_ - [enum-field](./src/fields/enum-field/enum-field.md) — _(no submodules)_ - [enum-field](./src/fields/enum-field/enum-field.md) — _(no submodules)_ - [json-field](./src/fields/json-field/json-field.md) — _(no submodules)_ - [json-field](./src/fields/json-field/json-field.md) — _(no submodules)_ - [number-field](./src/fields/number-field/number-field.md) — _(no submodules)_ - [number-field](./src/fields/number-field/number-field.md) — _(no submodules)_ - [port-field](./src/fields/port-field/port-field.md) — _(no submodules)_ - [port-field](./src/fields/port-field/port-field.md) — _(no submodules)_ - [string-field](./src/fields/string-field/string-field.md) — _(no submodules)_ - [string-field](./src/fields/string-field/string-field.md) — _(no submodules)_ - [url-field](./src/fields/url-field/url-field.md) — _(no submodules)_ - [url-field](./src/fields/url-field/url-field.md) — _(no submodules)_ - [dotenv](./src/loaders/dotenv/dotenv.md) — _(no submodules)_ - [dotenv](./src/loaders/dotenv/dotenv.md) — _(no submodules)_ - [object](./src/loaders/object/object.md) — _(no submodules)_ - [object](./src/loaders/object/object.md) — _(no submodules)_ - [common](./src/presets/common/common.md) — _(no submodules)_ - [common](./src/presets/common/common.md) — _(no submodules)_ - [server](./src/presets/server/server.md) — _(no submodules)_ - [server](./src/presets/server/server.md) — _(no submodules)_ - [schemas](./src/schemas/env.schemas.md) — _(no submodules)_ - [env.schemas](./src/schemas/env.schemas.md) — _(no submodules)_ - [coerce](./src/transforms/coerce/coerce.md) — _(no submodules)_ - [coerce](./src/transforms/coerce/coerce.md) — _(no submodules)_ - [types](./src/types/common.md) — _(no submodules)_ - [common](./src/types/common.md) — _(no submodules)_ - [utils](./src/utils/interpolation.md) — _(no submodules)_ - [interpolation](./src/utils/interpolation.md) — _(no submodules)_ - [create-env](./src/core/create-env/create-env.md) — _(no submodules)_- [field](./src/core/field/field.md) — _(no submodules)_- [field](./src/core/field/field.md) — _(no submodules)_- [validator](./src/core/validator/validator.md) — _(no submodules)_- [validator](./src/core/validator/validator.md) — _(no submodules)_- [env-error](./src/errors/env-error.md) — Provides the complete error class hierarchy and a value-object factory for `@suaveplan/env`. All classes extend `Suavep… - [error-codes](./src/errors/error-codes.md) — Defines and registers all stable error codes for the `@suaveplan/env` package using the `defineCodes` factory from `@su… - [array-field](./src/fields/array-field/array-field.md) — _(no submodules)_- [array-field](./src/fields/array-field/array-field.md) — _(no submodules)_- [boolean-field](./src/fields/boolean-field/boolean-field.md) — _(no submodules)_- [boolean-field](./src/fields/boolean-field/boolean-field.md) — _(no submodules)_- [email-field](./src/fields/email-field/email-field.md) — _(no submodules)_- [email-field](./src/fields/email-field/email-field.md) — _(no submodules)_- [enum-field](./src/fields/enum-field/enum-field.md) — _(no submodules)_- [enum-field](./src/fields/enum-field/enum-field.md) — _(no submodules)_- [json-field](./src/fields/json-field/json-field.md) — _(no submodules)_- [json-field](./src/fields/json-field/json-field.md) — _(no submodules)_- [number-field](./src/fields/number-field/number-field.md) — _(no submodules)_- [number-field](./src/fields/number-field/number-field.md) — _(no submodules)_- [port-field](./src/fields/port-field/port-field.md) — _(no submodules)_- [port-field](./src/fields/port-field/port-field.md) — _(no submodules)_- [string-field](./src/fields/string-field/string-field.md) — _(no submodules)_- [string-field](./src/fields/string-field/string-field.md) — _(no submodules)_- [url-field](./src/fields/url-field/url-field.md) — _(no submodules)_- [url-field](./src/fields/url-field/url-field.md) — _(no submodules)_- [dotenv](./src/loaders/dotenv/dotenv.md) — _(no submodules)_- [dotenv](./src/loaders/dotenv/dotenv.md) — _(no submodules)_- [object](./src/loaders/object/object.md) — _(no submodules)_- [object](./src/loaders/object/object.md) — _(no submodules)_- [common](./src/presets/common/common.md) — _(no submodules)_- [common](./src/presets/common/common.md) — _(no submodules)_- [server](./src/presets/server/server.md) — _(no submodules)_- [server](./src/presets/server/server.md) — _(no submodules)_- [schemas](./src/schemas/env.schemas.md) — _(no submodules)_- [env.schemas](./src/schemas/env.schemas.md) — _(no submodules)_- [coerce](./src/transforms/coerce/coerce.md) — _(no submodules)_- [coerce](./src/transforms/coerce/coerce.md) — _(no submodules)_- [types](./src/types/common.md) — _(no submodules)_- [common](./src/types/common.md) — _(no submodules)_- [utils](./src/utils/interpolation.md) — _(no submodules)_- [interpolation](./src/utils/interpolation.md) — _(no submodules)_- [create-env](./src/core/create-env/create-env.md) — _(no submodules)_- [field](./src/core/field/field.md) — _(no submodules)_- [field](./src/core/field/field.md) — _(no submodules)_- [validator](./src/core/validator/validator.md) — _(no submodules)_- [validator](./src/core/validator/validator.md) — _(no submodules)_- [env-error](./src/errors/env-error.md) — Provides the complete error class hierarchy and a value-object factory for `@suaveplan/env`. All classes extend `Suavep… - [error-codes](./src/errors/error-codes.md) — Defines and registers all stable error codes for the `@suaveplan/env` package using the `defineCodes` factory from `@su… - [array-field](./src/fields/array-field/array-field.md) — _(no submodules)_- [array-field](./src/fields/array-field/array-field.md) — _(no submodules)_- [boolean-field](./src/fields/boolean-field/boolean-field.md) — _(no submodules)_- [boolean-field](./src/fields/boolean-field/boolean-field.md) — _(no submodules)_- [email-field](./src/fields/email-field/email-field.md) — _(no submodules)_- [email-field](./src/fields/email-field/email-field.md) — _(no submodules)_- [enum-field](./src/fields/enum-field/enum-field.md) — _(no submodules)_- [enum-field](./src/fields/enum-field/enum-field.md) — _(no submodules)_- [json-field](./src/fields/json-field/json-field.md) — _(no submodules)_- [json-field](./src/fields/json-field/json-field.md) — _(no submodules)_- [number-field](./src/fields/number-field/number-field.md) — _(no submodules)_- [number-field](./src/fields/number-field/number-field.md) — _(no submodules)_- [port-field](./src/fields/port-field/port-field.md) — _(no submodules)_- [port-field](./src/fields/port-field/port-field.md) — _(no submodules)_- [string-field](./src/fields/string-field/string-field.md) — _(no submodules)_- [string-field](./src/fields/string-field/string-field.md) — _(no submodules)_- [url-field](./src/fields/url-field/url-field.md) — _(no submodules)_- [url-field](./src/fields/url-field/url-field.md) — _(no submodules)_- [dotenv](./src/loaders/dotenv/dotenv.md) — _(no submodules)_- [dotenv](./src/loaders/dotenv/dotenv.md) — _(no submodules)_- [object](./src/loaders/object/object.md) — _(no submodules)_- [object](./src/loaders/object/object.md) — _(no submodules)_- [common](./src/presets/common/common.md) — _(no submodules)_- [common](./src/presets/common/common.md) — _(no submodules)_- [server](./src/presets/server/server.md) — _(no submodules)_- [server](./src/presets/server/server.md) — _(no submodules)_- [schemas](./src/schemas/env.schemas.md) — _(no submodules)_- [env.schemas](./src/schemas/env.schemas.md) — _(no submodules)_- [coerce](./src/transforms/coerce/coerce.md) — _(no submodules)_- [coerce](./src/transforms/coerce/coerce.md) — _(no submodules)_- [types](./src/types/common.md) — _(no submodules)_- [common](./src/types/common.md) — _(no submodules)_- [utils](./src/utils/interpolation.md) — _(no submodules)_- [interpolation](./src/utils/interpolation.md) — _(no submodules)_- [create-env](./src/core/create-env/create-env.md) — _(no submodules)_- [field](./src/core/field/field.md) — _(no submodules)_- [field](./src/core/field/field.md) — _(no submodules)_- [validator](./src/core/validator/validator.md) — _(no submodules)_- [validator](./src/core/validator/validator.md) — _(no submodules)_- [env-error](./src/errors/env-error.md) — Provides the complete error class hierarchy and a value-object factory for `@suaveplan/env`. All classes extend `Suavep… - [error-codes](./src/errors/error-codes.md) — Defines and registers all stable error codes for the `@suaveplan/env` package using the `defineCodes` factory from `@su… - [array-field](./src/fields/array-field/array-field.md) — _(no submodules)_- [array-field](./src/fields/array-field/array-field.md) — _(no submodules)_- [boolean-field](./src/fields/boolean-field/boolean-field.md) — _(no submodules)_- [boolean-field](./src/fields/boolean-field/boolean-field.md) — _(no submodules)_- [email-field](./src/fields/email-field/email-field.md) — _(no submodules)_- [email-field](./src/fields/email-field/email-field.md) — _(no submodules)_- [enum-field](./src/fields/enum-field/enum-field.md) — _(no submodules)_- [enum-field](./src/fields/enum-field/enum-field.md) — _(no submodules)_- [json-field](./src/fields/json-field/json-field.md) — _(no submodules)_- [json-field](./src/fields/json-field/json-field.md) — _(no submodules)_- [number-field](./src/fields/number-field/number-field.md) — _(no submodules)_- [number-field](./src/fields/number-field/number-field.md) — _(no submodules)_- [port-field](./src/fields/port-field/port-field.md) — _(no submodules)_- [port-field](./src/fields/port-field/port-field.md) — _(no submodules)_- [string-field](./src/fields/string-field/string-field.md) — _(no submodules)_- [string-field](./src/fields/string-field/string-field.md) — _(no submodules)_- [url-field](./src/fields/url-field/url-field.md) — _(no submodules)_- [url-field](./src/fields/url-field/url-field.md) — _(no submodules)_- [dotenv](./src/loaders/dotenv/dotenv.md) — _(no submodules)_- [dotenv](./src/loaders/dotenv/dotenv.md) — _(no submodules)_- [object](./src/loaders/object/object.md) — _(no submodules)_- [object](./src/loaders/object/object.md) — _(no submodules)_- [common](./src/presets/common/common.md) — _(no submodules)_- [common](./src/presets/common/common.md) — _(no submodules)_- [server](./src/presets/server/server.md) — _(no submodules)_- [server](./src/presets/server/server.md) — _(no submodules)_- [schemas](./src/schemas/env.schemas.md) — _(no submodules)_- [env.schemas](./src/schemas/env.schemas.md) — _(no submodules)_- [coerce](./src/transforms/coerce/coerce.md) — _(no submodules)_- [coerce](./src/transforms/coerce/coerce.md) — _(no submodules)_- [types](./src/types/common.md) — _(no submodules)_- [common](./src/types/common.md) — _(no submodules)_- [utils](./src/utils/interpolation.md) — _(no submodules)_- [interpolation](./src/utils/interpolation.md) — _(no submodules)_- [create-env](./src/core/create-env/create-env.md) — _(no submodules)_- [field](./src/core/field/field.md) — _(no submodules)_ - [field](./src/core/field/field.md) — _(no submodules)_- [validator](./src/core/validator/validator.md) — _(no submodules)_ - [validator](./src/core/validator/validator.md) — _(no submodules)_- [env-error](./src/errors/env-error.md) — Provides the complete error class hierarchy and a value-object factory for `@suaveplan/env`. All classes extend `Suavep… - [error-codes](./src/errors/error-codes.md) — Defines and registers all stable error codes for the `@suaveplan/env` package using the `defineCodes` factory from `@su… - [array-field](./src/fields/array-field/array-field.md) — _(no submodules)_ - [array-field](./src/fields/array-field/array-field.md) — _(no submodules)_- [boolean-field](./src/fields/boolean-field/boolean-field.md) — _(no submodules)_ - [boolean-field](./src/fields/boolean-field/boolean-field.md) — _(no submodules)_- [email-field](./src/fields/email-field/email-field.md) — _(no submodules)_ - [email-field](./src/fields/email-field/email-field.md) — _(no submodules)_- [enum-field](./src/fields/enum-field/enum-field.md) — _(no submodules)_ - [enum-field](./src/fields/enum-field/enum-field.md) — _(no submodules)_- [json-field](./src/fields/json-field/json-field.md) — _(no submodules)_ - [json-field](./src/fields/json-field/json-field.md) — _(no submodules)_- [number-field](./src/fields/number-field/number-field.md) — _(no submodules)_ - [number-field](./src/fields/number-field/number-field.md) — _(no submodules)_- [port-field](./src/fields/port-field/port-field.md) — _(no submodules)_ - [port-field](./src/fields/port-field/port-field.md) — _(no submodules)_- [string-field](./src/fields/string-field/string-field.md) — _(no submodules)_ - [string-field](./src/fields/string-field/string-field.md) — _(no submodules)_- [url-field](./src/fields/url-field/url-field.md) — _(no submodules)_ - [url-field](./src/fields/url-field/url-field.md) — _(no submodules)_- [dotenv](./src/loaders/dotenv/dotenv.md) — _(no submodules)_ - [dotenv](./src/loaders/dotenv/dotenv.md) — _(no submodules)_- [object](./src/loaders/object/object.md) — _(no submodules)_ - [object](./src/loaders/object/object.md) — _(no submodules)_- [common](./src/presets/common/common.md) — _(no submodules)_ - [common](./src/presets/common/common.md) — _(no submodules)_- [server](./src/presets/server/server.md) — _(no submodules)_ - [server](./src/presets/server/server.md) — _(no submodules)_- [schemas](./src/schemas/env.schemas.md) — _(no submodules)_ - [env.schemas](./src/schemas/env.schemas.md) — _(no submodules)_- [coerce](./src/transforms/coerce/coerce.md) — _(no submodules)_ - [coerce](./src/transforms/coerce/coerce.md) — _(no submodules)_- [types](./src/types/common.md) — _(no submodules)_ - [common](./src/types/common.md) — _(no submodules)_- [utils](./src/utils/interpolation.md) — _(no submodules)_ - [interpolation](./src/utils/interpolation.md) — _(no submodules)_ ## Features - **Nine field builders**: `str`, `num`, `bool`, `enums`, `url`, `email`, `port`, `json`, `array` - **Fluent builder chains**: constraints, defaults, sensitive marking, and descriptions per field - **Pluggable loaders**: dotenv file, object (`process.env`), or custom loaders with priority ordering - **Three error modes**: `throw` (default), `collect` (partial data), `warn` (log and continue) - **Full-error accumulation**: reports every broken field in a single run, not just the first - **Sensitive value redaction**: `maskSensitive` replaces secret values with `****` before logging - **Preset libraries**: `commonFields` and `serverFields` for the most frequent env variables - **Zod runtime schemas**: for validation at serialisation boundaries - **100% Istanbul coverage**: foundation-grade reliability ## Installation ```bash bun add @suaveplan/env ``` ## Quick Start ```ts import { createEnv, str, num, bool } from '@suaveplan/env'; const env = createEnv({ schema: { HOST: str().default('localhost'), PORT: num().default(3000), DEBUG: bool().default(false), API_KEY: str().nonempty().sensitive(), }, source: process.env, }); // Full TypeScript types — no manual annotation needed console.log(env.HOST); // string console.log(env.PORT); // number console.log(env.DEBUG); // boolean console.log(env.API_KEY); // string ``` ## Field Builders | Factory | Output type | Key methods | |---|---|---| | `str()` | `string` | `trim`, `lowercase`, `uppercase`, `minLength`, `maxLength`, `pattern`, `nonempty`, `startsWith`, `endsWith`, `includes` | | `num()` | `number` | `min`, `max`, `integer`, `positive`, `nonNegative` | | `bool()` | `boolean` | `truthy(values)`, `falsy(values)` | | `enums(values)` | `"a" \| "b" \| …` | `caseInsensitive`, `getAllowedValues` | | `url()` | `string` | `protocols(list)`, `noTrailingSlash` | | `email()` | `string` | `normalise`, `pattern(regex)` | | `port()` | `number` | `min(n)`, `max(n)` | | `json()` | `T` (default `unknown`) | `validator(fn)` | | `array(itemField)` | `T[]` | `separator`, `noTrim`, `keepEmpty`, `minItems`, `maxItems` | All builders share: `optional()`, `default(value)`, `sensitive()`, `describe(text)`, `addRule(options)`. ## Loaders ```ts import { createEnv, str } from '@suaveplan/env'; import { dotenvLoader, objectLoader } from '@suaveplan/env/loaders'; const env = createEnv({ schema: { DB_URL: str().sensitive() }, loaders: [ dotenvLoader({ path: '.env' }), // from file objectLoader({ source: process.env }), // from process.env (wins) ], }); ``` Later loaders override earlier ones for the same key. `source` (if provided) overrides all loaders. ## Error Modes ```ts // Default: throws EnvValidationError with all failures listed const env = createEnv({ schema, source: process.env }); // Collect: returns partial data silently const env = createEnv({ schema, source: process.env, onError: 'collect' }); // Warn: logs each failure via console.warn, returns partial data const env = createEnv({ schema, source: process.env, onError: 'warn' }); ``` ## Prefix Support ```ts // Reads APP_HOST, APP_PORT from process.env; output keys are HOST, PORT const env = createEnv({ schema: { HOST: str().default('localhost'), PORT: num().default(3000) }, source: process.env, prefix: 'APP_', }); ``` ## Presets ```ts import { commonFields } from '@suaveplan/env/presets/common/common'; import { serverFields, databaseUrlField, sessionSecretField } from '@suaveplan/env/presets/server/server'; import { createEnv, str } from '@suaveplan/env'; const env = createEnv({ schema: { ...commonFields, // NODE_ENV, PORT, HOST, DEBUG, LOG_LEVEL DATABASE_URL: databaseUrlField(), SESSION_SECRET: sessionSecretField(), CUSTOM: str().optional(), }, source: process.env, }); ``` ## Sensitive Values ```ts import { validate, maskSensitive } from '@suaveplan/env/core/validator/validator'; import { str } from '@suaveplan/env'; const schema = { SECRET: str().sensitive(), PUBLIC: str() }; const result = validate({ schema, values: { SECRET: 'my-secret', PUBLIC: 'ok' } }); const safe = maskSensitive(schema, result.data); console.log(safe.SECRET); // "****" console.log(safe.PUBLIC); // "ok" ``` ## Errors ```ts import { EnvValidationError, CoercionError } from '@suaveplan/env/errors'; import { ENV_CODES } from '@suaveplan/env/errors'; try { createEnv({ schema, source: {} }); } catch (err) { if (err instanceof EnvValidationError) { console.log(err.code); // "ENV.VALIDATION_FAILED" console.log(err.errors); // [{ key, message }] } } ``` ## Zod Schemas Runtime schemas for validation at API or persistence boundaries: ```ts import { FieldConfigSchema, ValidationResultSchema } from '@suaveplan/env/schemas'; const result = FieldConfigSchema.safeParse(unknownPayload); ``` ## Module Reference | Co-located module | Description | |---|---| | [`src/core/create-env/create-env.md`](src/core/create-env/create-env.md) | `createEnv` orchestrator | | [`src/core/field/field.md`](src/core/field/field.md) | `BaseField` abstract base | | [`src/core/validator/validator.md`](src/core/validator/validator.md) | `validate` and `maskSensitive` | | [`src/errors/error-codes.md`](src/errors/error-codes.md) | `ENV_CODES` registry | | [`src/errors/env-error.md`](src/errors/env-error.md) | Error class hierarchy | | [`src/fields/string-field/string-field.md`](src/fields/string-field/string-field.md) | `str()` | | [`src/fields/number-field/number-field.md`](src/fields/number-field/number-field.md) | `num()` | | [`src/fields/boolean-field/boolean-field.md`](src/fields/boolean-field/boolean-field.md) | `bool()` | | [`src/fields/enum-field/enum-field.md`](src/fields/enum-field/enum-field.md) | `enums()` | | [`src/fields/url-field/url-field.md`](src/fields/url-field/url-field.md) | `url()` | | [`src/fields/email-field/email-field.md`](src/fields/email-field/email-field.md) | `email()` | | [`src/fields/port-field/port-field.md`](src/fields/port-field/port-field.md) | `port()` | | [`src/fields/json-field/json-field.md`](src/fields/json-field/json-field.md) | `json()` | | [`src/fields/array-field/array-field.md`](src/fields/array-field/array-field.md) | `array()` | | [`src/loaders/dotenv/dotenv.md`](src/loaders/dotenv/dotenv.md) | `parseDotenv`, `dotenvLoader` | | [`src/loaders/object/object.md`](src/loaders/object/object.md) | `objectLoader` | | [`src/transforms/coerce/coerce.md`](src/transforms/coerce/coerce.md) | Standalone coercion functions | | [`src/presets/common/common.md`](src/presets/common/common.md) | Common server field presets | | [`src/presets/server/server.md`](src/presets/server/server.md) | Server connection field presets | | [`src/schemas/env.schemas.md`](src/schemas/env.schemas.md) | Zod runtime schemas | | [`src/types/common.md`](src/types/common.md) | Shared TypeScript types | | [`src/utils/interpolation.md`](src/utils/interpolation.md) | `${VAR}` interpolation utilities |