Skip to main content
Bun reads your .env files automatically and provides idiomatic ways to read and write environment variables programmatically. You no longer need packages like dotenv or dotenv-expand.

Setting environment variables

.env files

Bun reads the following files automatically, listed in order of increasing precedence:
  1. .env
  2. .env.production, .env.development, or .env.test (based on the value of NODE_ENV)
  3. .env.local
Variables defined in files with higher precedence override those in files with lower precedence.
.env
FOO=hello
BAR=world

Command line

FOO=helloworld bun run dev
For a cross-platform solution, use Bun Shell. The bun exec command runs a shell command cross-platform:
bun exec 'FOO=helloworld bun run dev'
On Windows, package.json scripts called with bun run automatically use the Bun shell, making inline env vars cross-platform:
package.json
{
  "scripts": {
    "dev": "NODE_ENV=development bun --watch app.ts"
  }
}

Programmatically

Assign directly to process.env at runtime:
process.env.FOO = "hello";

Specifying .env files

Use --env-file to load a specific .env file instead of the defaults. You can pass multiple --env-file flags; later files take higher precedence.
# Load a single custom env file
bun --env-file=.env.staging src/index.ts

# Load multiple env files
bun --env-file=.env.base --env-file=.env.override run build

Disabling automatic .env loading

Use --no-env-file to skip automatic .env loading entirely. This is useful in production or CI environments where environment variables are injected by the platform.
bun run --no-env-file index.ts
You can also disable it in bunfig.toml:
bunfig.toml
# Disable loading .env files
env = false
Explicitly provided --env-file flags still load their files even when --no-env-file or env = false is set.

Reading environment variables

Access the current environment via process.env, Bun.env, or import.meta.env. All three are equivalent.
process.env.API_TOKEN;       // => "secret"
Bun.env.API_TOKEN;           // => "secret"
import.meta.env.API_TOKEN;   // => "secret"
To print all currently-set environment variables for debugging:
bun --print process.env

.env file syntax

Quotation marks

Bun supports double quotes, single quotes, and backtick template literals:
.env
FOO='single quoted'
BAR="double quoted"
BAZ=`backtick quoted`

Variable expansion

Environment variables are automatically expanded. You can reference previously-defined variables in later declarations:
.env
FOO=world
BAR=hello$FOO
process.env.BAR; // => "helloworld"
This is useful for constructing connection strings:
.env
DB_USER=postgres
DB_PASSWORD=secret
DB_HOST=localhost
DB_PORT=5432
DB_URL=postgres://$DB_USER:$DB_PASSWORD@$DB_HOST:$DB_PORT/mydb
To disable expansion for a specific variable, escape the $ with a backslash:
.env
FOO=world
BAR=hello\$FOO
process.env.BAR; // => "hello$FOO"

TypeScript

All process.env properties are typed as string | undefined by default:
Bun.env.SOME_VAR; // string | undefined
To add autocompletion and tell TypeScript to treat a variable as a non-optional string, use interface merging. Add the following declaration to any file in your project:
declare module "bun" {
  interface Env {
    MY_REQUIRED_VAR: string;
  }
}
Now process.env.MY_REQUIRED_VAR and Bun.env.MY_REQUIRED_VAR are typed as string (not string | undefined).

Bun-specific environment variables

These environment variables configure aspects of Bun’s own behavior:
VariableDescription
NODE_TLS_REJECT_UNAUTHORIZEDSet to 0 to disable SSL certificate validation. Use for testing only.
BUN_CONFIG_VERBOSE_FETCHSet to curl to log fetch request/response headers. Set to 1 for the same output without curl formatting.
BUN_RUNTIME_TRANSPILER_CACHE_PATHDirectory for the runtime transpiler cache. Set to 0 or empty string to disable caching.
TMPDIRDirectory for temporary files during bundling. Defaults to /tmp (Linux) or /private/tmp (macOS).
NO_COLORSet to 1 to disable ANSI color output.
FORCE_COLORSet to 1 to force ANSI color output even when NO_COLOR is set.
BUN_CONFIG_MAX_HTTP_REQUESTSMaximum concurrent HTTP requests for fetch and bun install. Defaults to 256.
BUN_CONFIG_NO_CLEAR_TERMINAL_ON_RELOADSet to true to prevent bun --watch from clearing the terminal on reload.
DO_NOT_TRACKSet to 1 to disable crash report uploads and telemetry.
BUN_OPTIONSPrepends CLI arguments to every Bun invocation. For example, BUN_OPTIONS="--hot" makes bun run dev behave like bun --hot run dev.

Runtime transpiler cache

For files larger than 50 KB, Bun caches transpiled output to speed up subsequent runs. The cache is global, content-addressable, and safe to delete at any time.
It is recommended to disable the transpiler cache when using ephemeral filesystems like Docker. Bun’s official Docker images disable this cache automatically.
To disable the cache:
BUN_RUNTIME_TRANSPILER_CACHE_PATH=0 bun run dev

Build docs developers (and LLMs) love