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
| Runtime | Minimum |
|---|---|
| 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 envaptThe 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.NodeEnvSourceis bound on import, so it readsprocess.envand the.envcascade, and the file APIs work. - Cloudflare Workers import from
envapt/workerd. There is no filesystem, so the file APIs are not available; bind aWorkerEnvSourcefrom theenvbinding exported viacloudflare:workersor in a fetch. - The browser imports from
envapt/browser. There is no filesystem orprocess.env, so seed aManualEnvSourcewith 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:
{ "compilerOptions": { "experimentalDecorators": true } }Deno. Enable the same flag in deno.json:
{ "compilerOptions": { "experimentalDecorators": true } }Bun. The functional API works when you run a .ts file directly. The decorator does not.
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.