---
title: @envlock/core API
description: Complete API reference for every public export in @envlock/core v0.1.0.
url: https://pr-1-7cfcfe393d12.thally.app/envlock-core-api
---

# @envlock/core API

Complete API reference for every public export in @envlock/core v0.1.0.

Complete API reference for `@envlock/core` v0.1.0.

## Constants

### FIELD_KINDS

```ts
const FIELD_KINDS: {
  string: "string";
  number: "number";
  integer: "integer";
  boolean: "boolean";
  port: "port";
  url: "url";
  enum: "enum";
  json: "json";
  duration: "duration";
  list: "list";
};
```

### ISSUE_CODES

```ts
const ISSUE_CODES: {
  missing: "missing";
  invalid: "invalid";
  unknown: "unknown";
};
```

### REDACTED_VALUE

```ts
const REDACTED_VALUE: "••••••"; // six bullet characters
```

The string used to mask secret values in error messages and redacted output.

### SCHEMA_KIND

```ts
const SCHEMA_KIND: "envlock.schema";
```

---

## The `env` builder namespace

Each factory method returns a `Field<T, true>` (required, non-secret) that
can be further configured with modifier methods.

| Builder | Output type | Constraints |
| --- | --- | --- |
| `env.string()` | `string` | none |
| `env.number()` | `number` | finite number |
| `env.integer()` | `number` | whole number |
| `env.boolean()` | `boolean` | `true`/`false`, `1`/`0`, `yes`/`no`, `on`/`off` (case-insensitive) |
| `env.port()` | `number` | integer 1–65535 |
| `env.url(options?)` | `string` | absolute URL; optionally restrict protocols via `UrlOptions` |
| ``env.enum(values)`` | literal union | one of the provided values |
| ``env.json()`` | `T` | valid JSON document |
| `env.duration()` | `number` (ms) | duration like `30s`, `5m`, `2h` |
| `env.list(options?)` | `string[]` | comma-separated list; custom separator via `ListOptions` |

### Duration units

| Unit | Milliseconds |
| --- | --- |
| `ms` | 1 |
| `s` | 1000 |
| `m` | 60000 |
| `h` | 3600000 |
| `d` | 86400000 |

A bare number (no unit suffix) is treated as milliseconds.

### UrlOptions

```ts
interface UrlOptions {
  readonly protocols?: readonly string[];
}
```

Restricts accepted URL protocols. For example,
`env.url({ protocols: ["https:"] })` only accepts HTTPS URLs.

### ListOptions

```ts
interface ListOptions {
  readonly separator?: string;
}
```

Default separator is `","`.

---

## Field interface

```ts
interface Field<T = unknown, Required extends boolean = boolean> {
  readonly kind: FieldKind;
  readonly isOptional: boolean;
  readonly hasDefault: boolean;
  readonly defaultValue?: T;
  readonly isSecret: boolean;
  readonly description?: string;
  readonly exampleValue?: string;
  readonly constraints?: string;
  readonly parse: (raw: string) => ParseOutcome<T>;
  optional(): Field<T, false>;
  default(value: T): Field<T, true>;
  secret(): Field<T, Required>;
  describe(text: string): Field<T, Required>;
  example(text: string): Field<T, Required>;
}
```

Fields are frozen and immutable. Every chain method returns a new field
instance. Calling `.default(value)` clears optional (`isOptional` becomes
`false`). Calling `.optional()` does not clear a previous default.

### Modifier methods

| Method | Returns | Effect |
| --- | --- | --- |
| `.optional()` | `Field<T, false>` | Marks the field as not required |
| `.default(value)` | `Field<T, true>` | Sets a fallback value; clears optional |
| `.secret()` | `Field<T, Required>` | Masks value in issues, examples, and `redact()` |
| `.describe(text)` | `Field<T, Required>` | Attaches a human-readable description |
| `.example(text)` | `Field<T, Required>` | Provides a sample value for `.env.example` rendering |

---

## Types

### AnyField

```ts
type AnyField = Field<unknown, boolean>;
```

### FieldKind

```ts
type FieldKind =
  | "string" | "number" | "integer" | "boolean" | "port"
  | "url" | "enum" | "json" | "duration" | "list";
```

### ParseOutcome

```ts
type ParseOutcome<T> =
  | { readonly ok: true; readonly value: T }
  | { readonly ok: false; readonly message: string };
```

---

## defineEnv

```ts
function defineEnv<Shape extends Record<string, AnyField>>(
  shape: Shape,
): EnvSchema<Shape>;
```

Creates a frozen schema from a shape object. Throws `TypeError` if any key
does not match the pattern `/^[A-Za-z_][A-Za-z0-9_]*$/`.

### EnvSchema

```ts
interface EnvSchema<Shape> {
  readonly kind: "envlock.schema";
  readonly shape: Shape;
  readonly keys: readonly string[];
}
```

### Infer

Maps a schema to its typed output object. Required and defaulted fields
produce required properties; optional fields produce optional properties.

```ts
type Infer<S extends EnvSchema> = /* mapped type */;
```

### isEnvSchema

```ts
function isEnvSchema(value: unknown): value is EnvSchema;
```

Type guard that checks `kind`, `keys`, and `shape`.

---

## parseEnv

```ts
function parseEnv<S extends EnvSchema>(
  schema: S,
  source: EnvSource,
  options?: ParseOptions,
): ParseResult<S>;
```

Validates `source` against `schema` without throwing.

### EnvSource

```ts
type EnvSource = Readonly<Record<string, string | undefined>>;
```

### ParseOptions

```ts
interface ParseOptions {
  readonly strict?: boolean;
}
```

### ParseResult

```ts
type ParseResult<S> =
  | { ok: true; values: Infer<S>; issues: readonly [] }
  | { ok: false; issues: readonly EnvIssue[] };
```

### Parsing rules

- Both `undefined` and `""` count as absent.
- Absent + `.default()` yields the default value.
- Absent + `.optional()` skips the key in the output.
- Absent + required = `missing` issue.
- Parse failure = `invalid` issue.
- `strict: true` adds `unknown` issues for unrecognized source keys (sorted
  alphabetically).
- Issues are ordered by declaration order, then unknowns.
- Secret fields: the `received` property is masked to `REDACTED_VALUE`.

### EnvIssue

```ts
interface EnvIssue {
  readonly key: string;
  readonly code: IssueCode; // "missing" | "invalid" | "unknown"
  readonly message: string;
  readonly received?: string;
}
```

---

## loadEnv

```ts
function loadEnv<S extends EnvSchema>(
  schema: S,
  source?: EnvSource,
  options?: ParseOptions,
): Infer<S>;
```

Convenience wrapper around `parseEnv`. Source defaults to `process.env`,
options to `{}`. Throws `EnvValidationError` on failure.

### EnvValidationError

```ts
class EnvValidationError extends Error {
  readonly issues: readonly EnvIssue[];
}
```

Name is `"EnvValidationError"`. Message format:

```text
Environment validation failed (N issues):
  - KEY: message (received "val")
  ...
```

---

## formatIssues

```ts
function formatIssues(issues: readonly EnvIssue[]): string;
```

Returns an indented bullet list of issues suitable for terminal output.

---

## parseDotenv

```ts
function parseDotenv(text: string): Record<string, string>;
```

Parses `.env` file text into a key-value record. Never throws.

**Supported syntax:**

- `KEY=value` and `export KEY=value`
- `#` comments and inline comments (` #`)
- Single-quoted and double-quoted values
- Backslash escapes in double quotes: `\n`, `\r`, `\t`, `\"`, `\\`, `\$`
- Multi-line quoted values
- Empty values (`KEY=`)
- CRLF normalized to LF
- Malformed lines are skipped
- Later duplicates win

## formatDotenv

```ts
function formatDotenv(
  record: Readonly<Record<string, string>>,
): string;
```

Serializes a record to `.env` format in key order. Quotes and escapes values
only when needed. Round-trips cleanly with `parseDotenv`.

---

## renderExample

```ts
function renderExample(
  schema: EnvSchema,
  options?: RenderExampleOptions,
): string;
```

Generates `.env.example` text from a schema.

### RenderExampleOptions

```ts
interface RenderExampleOptions {
  readonly header?: readonly string[];
}
```

Default header lines:

```text
# Environment contract rendered by envlock.
# Copy to .env and fill in the values; never commit real secrets here.
```

Each variable is rendered with a description comment (if set), a meta comment
(type, optional/required, default, constraints, secret), then the `KEY=value`
line. Secret fields render as `KEY=` (no value). Secret defaults are shown as
`(hidden)` in the meta comment.

---

## diffEnv

```ts
function diffEnv(schema: EnvSchema, source: EnvSource): EnvDiff;
```

Runs `parseEnv` with `strict: true` and partitions the issues.

### EnvDiff

```ts
interface EnvDiff {
  readonly missing: readonly string[];
  readonly unknown: readonly string[];
  readonly invalid: readonly EnvIssue[];
  readonly ok: boolean;
}
```

---

## describeSchema

```ts
function describeSchema(schema: EnvSchema): SchemaDescription[];
```

Returns a structured description of every variable in the schema.

### SchemaDescription

```ts
interface SchemaDescription {
  readonly key: string;
  readonly type: FieldKind;
  readonly required: boolean;
  readonly hasDefault: boolean;
  readonly default?: unknown;
  readonly secret: boolean;
  readonly description?: string;
  readonly example?: string;
  readonly constraints?: string;
}
```

Default values are masked for secret fields. The `example` property is omitted
for secret fields.

---

## redact

```ts
function redact<T extends Readonly<Record<string, unknown>>>(
  values: T,
  schema: EnvSchema,
): { readonly [K in keyof T]: T[K] | string };
```

Returns a shallow copy of `values` with every `.secret()` field replaced by
`"••••••"`. The input is never mutated.