# The .env Surprise: Why Your dotenv Configuration Has No Effect in Bun

For Node.js developers, the workflow is muscle memory: need environment variables? Install `dotenv`, call `config()`, and the variables from your `.env` file are ready to go. However, when you bring this habit to Bun, the newer, blazing-fast JavaScript runtime, you'll encounter a surprise—a bit of "magic" that renders your `dotenv` setup seemingly useless.

It's an anomaly that has stumped many developers: You have both a `.env` and a `.env.local` file. You explicitly call `dotenv` in your code, which should load `.env`. But when you run it, Bun loads the variables from `.env.local` instead.

This isn't a bug. It's a fundamental feature that showcases how Bun thinks differently.

---

### The Surprising Scenario

Imagine the following simple project structure:

`.env`

```typescript
DATABASE_URL="postgresql://default_user@db/common_database"
```

`.env.local`

```typescript
DATABASE_URL="postgresql://local_user@db/my_special_database"
```

`server.js`

JavaScript

```typescript
// The old habit from the Node.js world
import 'dotenv/config';

console.log(`Connecting to database using: ${process.env.DATABASE_URL}`);
```

Based on pure `dotenv` logic, the output you'd expect would come from the `.env` file, as `dotenv.config()` targets that file by default.

However, when you run `bun run server.js`, the output that appears in your console is:

```typescript
Connecting to database using: postgresql://local_user@db/my_special_database
```

The value from `.env.local` wins. The `dotenv` package you imported appears to have been completely ignored. What's really going on?

---

### Unraveling the "Magic": The Bun Runtime Acts First

The answer lies in the order of execution. Unlike Node.js, which is a "blank canvas," **Bun is a "batteries-included" runtime**. One of those "batteries" is a highly efficient, *native* environment variable loader.

Here is the actual sequence of events when you run `bun run server.js`:

1. **Bun Takes Control (Before Your Code Runs):** When the `bun run` command is executed, **before** a single line of your `server.js` is touched, the Bun runtime itself scans your project directory.
    
2. **Native Loading by Bun:** Bun automatically discovers all relevant `.env` files. It loads them in a predetermined order of precedence, where more specific files override more general ones. The rule is: `.env.local` **always overrides** `.env`.
    
3. `process.env` is Pre-populated: After this step, the global `process.env` object has already been populated by Bun. In our case, `process.env.DATABASE_URL` is already set to `"postgresql://local_user@db/my_special_database"`.
    
4. **Your Code Execution Begins:** Only after all this preparation is complete does Bun start executing the code inside `server.js`.
    
5. **The Futile** `dotenv` Call: Your code reaches the `import 'dotenv/config'` line. The `dotenv` package runs and reads the `.env` file. However, when it's about to inject `DATABASE_URL` into `process.env`, it sees that the variable **already exists**. The default behavior of `dotenv` is **not to overwrite** existing variables. As a result, its call has no effect.
    

In short, Bun has already set the stage. The `dotenv` package you called arrived at a party that was already over.

---

### What This Means for You

Understanding this behavior is critical for working efficiently with Bun.

1. **Ditch** `dotenv` from Your Bun Projects: You simply don't need it. Relying on Bun's native loader is cleaner, faster, and removes one dependency from your project.
    
2. **Trust Bun's Conventions:** Leverage Bun's built-in `.env` precedence system. Use `.env` for team-wide defaults, `.env.development` or `.env.production` for environment-specific settings, and `.env.local` for your local overrides that should never be committed to Git.
    
3. **A New Mindset:** This is a perfect example of how Bun isn't just a "faster Node.js." It's an ecosystem with its own design philosophy that aims to simplify the modern development workflow.
    

So, the next time you see "weird" behavior in Bun, remember that it's often not a bug, but a clever feature designed to make your life easier—even if it means unlearning a few old habits.
