Frameworks

Bun

Native Bun support via a preload hook or a direct import.

Install

bash
bun add @goenvless/env

Add the loader to your bunfig.toml:

bunfig.toml
preload = ["@goenvless/env/register"]

/register runs the loader with a top-level await, so the preload does not resolve until the variables are fetched, decrypted and in place. Every bun run and bun test that picks up this bunfig.toml boots with variables already loaded, requiring no source changes.

Direct import

If you prefer code-side, import /register first, then read env:

server.ts
import '@goenvless/env/register';
import { env } from '@goenvless/env/server';
import { serve } from 'bun';

serve({ port: env.PORT, fetch: handler });

/register is a dependency of this module, so its top-level await resolves before the file body runs and env is loaded by the time serve is called. The file has to be ESM. require('@goenvless/env/register') throws instead of loading anything, because a require cannot block on the fetch and decrypt.

Use it

ts
import { env } from '@goenvless/env/server';

const db = new Bun.SQL(env.DATABASE_URL);

This snippet assumes the bunfig.toml preload above. Without that preload, or an awaited load(), the first read throws Envless env is not loaded yet. Import '@goenvless/env/register' or await load() first.

/server exposes every variable, server and client visibility alike, and coerces a value to a number or a boolean when the variable declares that type. Everything else stays a string.

Bun-specific notes

  • Bun.env mirrors process.env, so loaded values show up there too, with one exception. A variable whose name changes how a process or its children execute code is decrypted and readable through env, but deliberately never written into the process environment: NODE_OPTIONS, NODE_PATH, NODE_REPL_EXTERNAL_MODULE, ELECTRON_RUN_AS_NODE, LD_PRELOAD, LD_LIBRARY_PATH, LD_AUDIT, DYLD_INSERT_LIBRARIES, DYLD_LIBRARY_PATH, DYLD_FRAMEWORK_PATH, PATH, BUN_INSPECT, BUN_INSPECT_CONNECT_TO, RUBYOPT, RUBYLIB, BUNDLE_GEMFILE, GEM_HOME, GEM_PATH, PYTHONPATH, PYTHONHOME, PYTHONSTARTUP, PYTHONUSERBASE, PHPRC, PHP_INI_SCAN_DIR, ENVLESS_CLIENT_ENV and ENVLESS_INJECTED. The loader prints a warning naming the ones it refused.
  • Native Web Crypto is used for decryption, so no polyfill is needed.
  • Loaded values never clobber variables already set in the ambient environment. process.env keeps the ambient value, while env returns the Envless one.

CI with Bun

On a runner, provide the machine credential set before bun run: ENVLESS_TOKEN, ENVLESS_KEY (or ENVLESS_PASSPHRASE), ENVLESS_PROJECT, and ENVLESS_ENV. ENVLESS_TOKEN has to be a machine key starting with ev_sk_, anything else is refused. ENVLESS_PROJECT and ENVLESS_ENV can come from a committed .envless file instead. See Machine & CI access.