Upgrade @arki/env 0.0.11 to 0.1.0

For @arki/[email protected] · source docs/upgrades/0.0.11-to-0.1.0.md

Every app that calls defineEnv must act: validation now runs in every environment, so builds without secrets need SKIP_ENV_VALIDATION=1. Apps that never use secret() or the zod types of secret() can skip steps 2 and 3.

What changed

  • secret() takes any Standard Schema (zod, valibot, arktype, hand-written) and returns a Standard Schema, not a zod schema. .optional() is still there: it accepts a missing variable and leaves undefined unwrapped. The result no longer has zod methods such as .parse; use secret(schema)['~standard'].validate(value).

    A rejected secret's issues keep their path but get a fixed message, because some validators (valibot) repeat the received value in theirs and defineEnv logs issues.

  • Validation now runs in production by default. defineEnv used to skip validation whenever NODE_ENV !== 'development', so an app without an explicit skipValidation booted production on an unchecked config. The default now skips only when CI is set (Docker build stages) or during lint runs, the same rule most apps already passed by hand. Apps that set options.skipValidation are unaffected.

    New secret(schema), reveal(value) and Redacted (from @arki/env/core): a secret variable becomes a Redacted value that prints as [redacted] in logs, JSON, template strings and util.inspect, and is read with a deliberate reveal(env.KEY). reveal also accepts the raw string, for runs where validation is skipped.

  • defineEnv() server, client and shared take records of any Standard Schema (Zod, Valibot, ArkType, hand-written), not only ZodType; values are typed as each schema's output. @arki/env/dot: EnvDotOptions, EnvServices and env() take Record<string, StandardSchemaV1> instead of Record<string, ZodType>.

  • Breaking: defineEnv now validates in every environment. CI and lint runs no longer skip validation. The only implicit opt-out is SKIP_ENV_VALIDATION=1 (exactly 1); set it only in build stages that run without secrets. options.skipValidation still overrides it. The @arki/env/dot plugin now validates at boot and fails with ARKI_ENV_PLUGIN_E001 (new ENV_PLUGIN_ERROR_CODES), and EnvServices['env'] is derived from defineEnv without a cast.

Public API changes

  • secret() now returns a Standard Schema, not a zod schema. It has no .parse. .optional() still works.
  • defineEnv server, client and shared accept any Standard Schema, not only zod.
  • @arki/env/dot: EnvDotOptions, EnvServices and env() take Record<string, StandardSchemaV1>. The plugin validates at boot and fails with ARKI_ENV_PLUGIN_E001.
  • New exports: reveal, Redacted, ENV_PLUGIN_ERROR_CODES.

Steps

  1. Find builds that run without secrets (Docker build stages, lint, CI). defineEnv no longer skips validation there. Set SKIP_ENV_VALIDATION=1 (exactly 1) in those stages only.

    # before: CI=1 skipped validation
    CI=1 bun run build
    # after
    SKIP_ENV_VALIDATION=1 bun run build
  2. Replace zod methods on secret() results. Use the Standard Schema call.

    // before
    const key = secret(z.string()).parse(value);
    // after
    const result = secret(z.string())['~standard'].validate(value);
  3. Read secrets with reveal. A secret prints as [redacted] in logs and JSON.

    // after
    import { reveal } from '@arki/env/core';
     
    // before
    const key = env.API_KEY;
     
    const key = reveal(env.API_KEY);
  4. Dot apps: expect ARKI_ENV_PLUGIN_E001 at boot when a variable is missing. Fix the variable. Do not add a skip.

Verify

Run the app's boot with a missing required variable and confirm it fails. Run bun run typecheck in the app to catch .parse calls on secret().

All docs for @arki/[email protected]