Config

The @contract-kit/config package provides environment-first configuration with schema validation. Define your env vars with a schema, validate them at startup, and get a fully typed config object.

bun add @contract-kit/config

Usage

import { z } from "zod";
import { defineEnv } from "@contract-kit/config";

const env = defineEnv({
  schema: z.object({
    NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
    PORT: z.coerce.number().int().default(3000),
    DATABASE_URL: z.string().min(1, "DATABASE_URL is required"),
  }),
});

export const config = env.load();
// config.NODE_ENV, config.PORT, config.DATABASE_URL — fully typed

Prefix filtering

Use prefix to scope env vars. The prefix is stripped from keys before validation:

const env = defineEnv({
  schema: z.object({
    DATABASE_URL: z.string(),
    SECRET_KEY: z.string(),
  }),
  prefix: "APP_",
});

// Reads APP_DATABASE_URL and APP_SECRET_KEY from process.env
// Returns { DATABASE_URL, SECRET_KEY }
export const config = env.load();

Testing

Pass a custom env object instead of reading from process.env:

const config = env.load({
  env: {
    DATABASE_URL: "sqlite://test.db",
    SECRET_KEY: "test-secret",
  },
});

Schema libraries

Works with any Standard Schema library — Zod, Valibot, ArkType, etc. Async validators are not supported.

Error handling

Invalid configuration throws with a descriptive prefix:

[Contract Kit env] Invalid environment: DATABASE_URL is required
[Contract Kit env] Invalid environment for prefix "APP_": SECRET_KEY is required