Compatibility

Runtime support, engine versions, module formats, per-runtime builds, and how decorators behave across runtimes.

envapt runs on Node, Bun, and Deno with the same API and zero runtime dependencies. It also runs on Cloudflare Workers (workerd) and in the browser, where you bind an environment source yourself and there is no .env cascade. The functional reader API works on every runtime with no build step. The @Envapt decorator is TypeScript-only and has per-runtime requirements, covered below.

Engine versions

RuntimeMinimum
Node>=20
Bun>=1.3
Deno>=2.5

Each release is tested against Node 20, 22, and 24, plus Bun and Deno.

Cloudflare Workers and the browser have no semver engine; the right build is selected by the package exports conditions (below), not by an engine version.

Install

pnpm add envapt

The Deno tab installs from JSR; you can also use the npm specifier with deno add npm:envapt.

Module formats

envapt ships both ESM and CommonJS with type definitions for each, so import and require both resolve. There are no runtime dependencies.

Per-runtime builds

The package exports conditions select a build per runtime:

  • Node, Bun, and Deno resolve the Node build from envapt. NodeEnvSource is bound on import, so it reads process.env and the .env cascade, and the file APIs work.
  • Cloudflare Workers import from envapt/workerd. There is no filesystem, so the file APIs are not available; bind a WorkerEnvSource from the env binding exported via cloudflare:workers or in a fetch.
  • The browser imports from envapt/browser. There is no filesystem or process.env, so seed a ManualEnvSource with the values your bundler injects.

The workerd and browser builds contain no node: imports. Bind a source before your first read; see Sources.

On Workers and the browser, import from envapt/workerd and envapt/browser. These entries carry the matching types, which omit the five file-only APIs, so calling one is a compile error rather than a runtime FileApiUnsupported. TypeScript does not apply the workerd / browser conditions on its own, so bare envapt leaves you on the Node types, where those APIs look available.

Decorators per runtime

@Envapt is a legacy TypeScript decorator, so it needs experimentalDecorators. The functional API does not, so if you cannot enable the flag on a given runtime, the readers still work.

Node. Transpile with your usual toolchain (tsc, tsx, and so on) with:

tsconfig.json
{ "compilerOptions": { "experimentalDecorators": true } }

Deno. Enable the same flag in deno.json:

deno.json
{ "compilerOptions": { "experimentalDecorators": true } }

Bun. The functional API works when you run a .ts file directly. The decorator does not.

DANGER

Bun emits TC39 (Stage 3) decorators and ignores experimentalDecorators (bun#27575), so @Envapt does not work when you run a .ts entry through Bun directly. The functional API (Envapter.get, getNumber, and the rest) is unaffected. To use the decorator on Bun, precompile with tsc, tsdown, or Vite and run the compiled JavaScript.

On this page