For the most part, Varlock just works with Bun the same way it works with Node.js, and other JavaScript integrations work the same way.
Conflicts with Bun’s .env loading
Section titled “Conflicts with Bun’s .env loading”Bun does its own automatic loading of .env files, based on the current value of NODE_ENV (or BUN_ENV), which it defaults to development if not set. This causes problems when bun decides to load .env.development and passes those env vars into varlock.
The best way to fix this is to disable bun’s automatic loading of .env files in your bunfig.toml file:
env = falseYou may also use the --no-env-file CLI flag when invoking scripts with bun/bunx.
Note that if you are building a standalone executable using bun build, you can use the --no-compile-autoload-dotenv flag to disable this behavior in the final executable.
Running your code
Section titled “Running your code”Launch bun through varlock run. The resolved env is in place before bun starts, so everything sees it, including Bun’s native clients (RedisClient, s3, sql) that read env vars at startup:
varlock run -- bun src/index.tsvarlock run -- bun testYou can put this in your package.json scripts:
{ "scripts": { "start": "varlock run -- bun src/index.ts", "test": "varlock run -- bun test" }}To use varlock’s ENV object, log redaction, and leak detection, also import 'varlock/auto-load' at the top of your entry file. When launched by varlock run, it reuses the injected env instead of resolving again.
Compiled executables
Section titled “Compiled executables”bun build --compile bundles the varlock/auto-load runtime code into your executable, but it does not bundle the separate Varlock CLI that resolves your config. If the executable resolves config when it starts, your deployment must also include the installed varlock package and its dependencies. The executable looks for node_modules/.bin/varlock in its directory and each parent directory (stopping at the git repository root, if there is one), and only falls back to a varlock on PATH if no local install is found.
For example, this monorepo layout keeps the CLI available to the compiled server:
apps/server/dist/serverapps/server/node_modules/.bin/varlockIf your deployment platform installs or prunes dependencies, declare varlock as a production dependency in a package whose node_modules directory is deployed with the executable.
You can also launch the executable through the CLI. This resolves the config before the application starts, so the bundled varlock/auto-load code reuses the injected environment instead of looking for the CLI again:
varlock run -- ./dist/serverIf your deployment otherwise contains only the compiled executable, install the standalone Varlock binary in the deployment environment and launch the application through varlock run.
Using a preload script (not recommended)
Section titled “Using a preload script (not recommended)”Bun can run varlock/auto-load as a preload script configured in bunfig.toml, so you can skip varlock run and the import in your code. We don’t recommend this: it only covers some commands, and one of its failure modes is silent. If you still want to use it, understand these limits first:
- Bun native clients read the startup environment. A preload sets
process.envafter the process has started. Bun’s native clients that fall back to env vars when created without config (for examplenew RedisClient()readingREDIS_URL, or the defaults3andsqlclients) read the environment the process started with. They will not see values from the preload. Depending on the client, they either fall back to their defaults (e.g.,RedisClientquietly connects tolocalhost:6379) or fail with a missing-config error. Pass config explicitly (e.g.,new RedisClient(ENV.REDIS_URL)) or usevarlock run. This also applies toimport 'varlock/auto-load'in your code. bun testneeds its own entry. The top-levelpreloadapplies to code run by Bun’s runtime (bun <file>, andbun runscripts orbunx --buntools that execute under Bun).bun testignores it and only uses[test] preload.- Anything run by Node skips it. A
package.jsonscript that callsnode, or a tool with anodeshebang run via plainbunxorbun run, runs under Node, so the preload does not apply. - It affects every bun command in that directory. If your env fails validation, unrelated commands fail too.
- Do not use it with framework integrations. Those integrations watch your
.envfiles to trigger live-reloading.
preload = ["varlock/auto-load"]
[test]preload = ["varlock/auto-load"]