Why Bun Breaks Your Dependency Tree

I switched to Bun for the speed boost and immediately hit a wall. bun install kept throwing "incorrect peer dependency" warnings that made zero sense. Everything seemed to install fine, but then ESLint would break with cryptic errors like EREQUIRE_ESM or my TypeScript config would just... not work.

The Real Problem (Not the Academic Bullshit)

Here's what actually happens: npm is conservative as hell when picking versions. If package A wants eslint@8 and package B is okay with eslint@8 || eslint@9, npm goes with ESLint 8 because it satisfies everyone without breaking shit.

Bun says "fuck it, let's go with the latest" and installs ESLint 9. Then it spams you with warnings because half your packages were expecting ESLint 8 and now they're pissed off.

This GitHub issue was opened December 2024 and already has 3 reactions from developers hitting the same wall. The issue shows exact examples of ESLint version conflicts with @typescript-eslint/utils@8.18.0 expecting ^8.57.0 || ^9.0.0 but Bun choosing v9 anyway. The Bun team assigned it but fixing requires rewriting their entire dependency resolver.

What You'll Actually See

Here's the pain you'll experience:

The Error Spam: After bun install, your terminal gets flooded with:

warn: incorrect peer dependency \"eslint@9.16.0\" 
warn: incorrect peer dependency \"eslint@9.16.0\"
warn: incorrect peer dependency \"eslint@9.16.0\"

Then Your Linter Dies: You run bunx eslint src/ and get:

Error [ERR_REQUIRE_ESM]: require() of ES module not supported

This ERR_REQUIRE_ESM error happens when ESLint 9's ESM-first approach conflicts with packages expecting CommonJS.

Or TypeScript Gets Confused: Your `@typescript-eslint` rules just... don't work. No obvious error, they're just ignored.

My 3-Hour Debugging Session

I spent an entire afternoon trying to figure out why ESLint worked fine with npm but broke with Bun. Same fucking project, same package.json. Made no sense.

The smoking gun was comparing dependency trees:

npm install
npm ls eslint
## eslint@8.57.0

rm -rf node_modules package-lock.json  
bun install
bun pm ls | grep eslint
## eslint@9.16.0

Bun picked a different ESLint version even though my package.json said \"eslint\": \"^8.57.0\". Why? Because some buried dependency had eslint@^8.0.0 || ^9.0.0 in their peer deps and Bun just decided "fuck it, 9 is newer" without asking me.

Platform-Specific Gotchas

Windows: The Windows PATH limit will fuck you. Bun's `node_modules` structure is different and some Windows setups can't handle the longer paths. You'll get `ENAMETOOLONG` errors.

Node 18.2.0: There's a specific Node version that breaks Bun's ESLint integration. Upgrade to 18.3.0+ or downgrade to 18.1.x.

M1 Macs: Some native dependencies get confused about architectures when Bun resolves different versions than npm. Especially `@esbuild/` packages.

I wasted hours trying theoretical solutions before finding what actually works. The fixes below are battle-tested - I use them daily on production apps.

![ESLint Logo](https://eslint.org/assets/images/logo/eslint-logo-color.svg)

ESLint Logo

Fixes That Actually Work (From Someone Who's Been There)

The Nuclear Option: Force the Versions

This is what saved my ass after wasting 2 hours trying everything else. Add this to your `package.json` and tell Bun to stop being clever using Yarn-style resolutions:

{
  "resolutions": {
    "eslint": "8.57.0",
    "@typescript-eslint/eslint-plugin": "7.18.0",
    "@typescript-eslint/parser": "7.18.0"
  }
}

Then nuke everything and start over:

rm -rf node_modules bun.lockb package-lock.json
bun install

This forces Bun to use the versions that actually work together instead of its "optimized" bullshit choices. Takes 30 seconds to implement. Wish I'd started with this instead of wasting 2 hours debugging.

Pin Everything Early (Learn From My Mistakes)

If you're starting a new project, pin your major dependencies immediately. Don't trust version ranges with Bun - you'll pay for it later.

Instead of this:

{
  "devDependencies": {
    "eslint": "^8.0.0",
    "@typescript-eslint/eslint-plugin": "^7.0.0"
  }
}

Do this from day one:

{
  "devDependencies": {
    "eslint": "8.57.0",
    "@typescript-eslint/eslint-plugin": "7.18.0",
    "@typescript-eslint/parser": "7.18.0"
  }
}

I learned this the hard way when updating a 6-month-old project. What worked fine in January suddenly shit the bed in July because Bun's resolver decided to get "smarter".

The --exact Flag (When You Install New Stuff)

Every time you add a new package, use --exact:

## This will bite you later
bun add --dev eslint @typescript-eslint/eslint-plugin

## This saves you from future pain
bun add --exact --dev eslint@8.57.0 @typescript-eslint/eslint-plugin@7.18.0

Yeah, it's more typing. But spending 5 extra seconds typing is better than spending 3 hours debugging why your linter suddenly stopped working.

Bunfig.toml - The Last Resort

If nothing else works, you can try telling Bun to behave more like npm using a `bunfig.toml` configuration file:

## bunfig.toml
[install]
exact = true
peer = false

Warning: This worked fine on Bun v1.1.x but fucked up some projects when v1.2.x came out. As of Bun 1.2.21 (August 2025), it's still a crapshoot whether this will work for your project. Test it and have npm ready as backup.

Just Use npm for Install (I'm Not Ashamed)

For complex projects with 100+ dependencies, I gave up and went hybrid:

## Install with npm (it just works)
npm install

## Run everything else with Bun (still fast)
bun run dev
bun run build  
bun test

My package.json scripts:

{
  "scripts": {
    "deps": "npm install",
    "dev": "bun run dev",
    "build": "bun run build"
  }
}

You lose some speed on installs but gain sanity. Sometimes that's worth it.

Framework-Specific Gotchas

Next.js 14: The `eslint-config-next` package is especially broken with Bun. Took me forever to find this config that actually works:

{
  "resolutions": {
    "eslint": "8.57.0"
  },
  "devDependencies": {
    "eslint": "8.57.0",
    "eslint-config-next": "14.2.5"
  }
}

Don't try to use ESLint 9 with Next.js 14. It will break in subtle ways.

Vite Projects: Usually work fine but watch out for `@vitejs/plugin-react`. It has peer dependency issues with newer ESLint versions.

When Things Still Don't Work

Clear everything and try again:

rm -rf node_modules bun.lockb package-lock.json yarn.lock
bun pm cache rm  # Clear Bun's cache too
bun install

Check what Bun actually installed:

bun pm ls | grep eslint
## Compare with what you expected

Test immediately:

bunx eslint --version  # Should match your pinned version
bunx eslint src/       # Should not throw errors

If it still doesn't work after this, your dependency tree is probably too complex for Bun to handle correctly. Time to switch back to npm for installations.

Real talk: Bun is fast as hell but its dependency resolution is still fucked. These tricks will solve most of your problems, but that last 10% is where you'll lose your mind debugging weird edge cases.

Once you get Bun working, the next step is preventing this nightmare from happening again. The prevention strategies ahead will save you from repeating my mistakes.

Questions From Developers Who've Hit the Same Wall

Q

Why the hell do I get these warnings when everything seems to work?

A

Because Bun is overly fucking dramatic.

Those "incorrect peer dependency" warnings usually mean "I installed a slightly different version than expected" not "your entire project is fucked."The warnings show up when Bun installs ESLint 9 but your Type

Script plugin expects ESLint 8. It might work fine, but Bun floods your terminal with warnings anyway. Quick fix: Just force the versions to match:json{"resolutions": {"eslint": "8.57.0"}}

Q

Can I just ignore these stupid warnings?

A

For minor version differences: Yeah, usually safe to ignore.For major version differences: Don't ignore those. That way lies madness.I ignored major version mismatches once and spent a day debugging why my ESLint rules weren't working. The plugin was silently failing because it couldn't handle the newer ESLint version.

Q

My TypeScript ESLint setup is completely broken. What do I do?

A

Pin everything in the TypeScript ESLint ecosystem:json{"resolutions": {"eslint": "8.57.0","@typescript-eslint/eslint-plugin": "7.18.0","@typescript-eslint/parser": "7.18.0"}}Then nuke and rebuild:bashrm -rf node_modules bun.lockbbun installThis finally fixed it for me after trying everything else. ESLint 9 + TypeScript ESLint is still a mess with weird compatibility issues.

Q

Why does Bun pick different versions than npm for the same package.json?

A

Because Bun's resolver is "smarter" (read: broken). When given a choice between ESLint 8 and ESLint 9, npm picks the safe option (8), Bun picks the latest (9).GitHub issue #15711 has been tracking this for months. The Bun team knows it's broken but fixing it means rewriting their entire dependency resolver.

Q

Should I just go back to npm?

A

Depends on your pain tolerance:Stick with Bun if:

  • You can fix it with resolutions (takes 5 minutes)

  • The speed boost is worth the occasional headache

  • You're only dealing with simple projectsSwitch back to npm if:

  • You have 100+ dependencies and complex peer dependency chains

  • You're working on a team and can't afford to spend time debugging this bullshit

  • It's a production app and you need it to just fucking workMy approach:

Use npm for installs, Bun for everything else:bashnpm install # Just worksbun run dev # Still fast

Q

How do I avoid this bullshit in the future?

A

Pin your major dependencies from day one:json{"devDependencies": {"eslint": "8.57.0","typescript": "5.5.4"}}Don't trust version ranges with Bun. I learned this after the third time my project broke on bun install because some dependency updated and Bun chose a new "optimal" version.Keep a list of versions that work together and don't update unless you have to. Save yourself the debugging time.

![TypeScript Logo](https://www.typescriptlang.org/icons/icon-512x512.png)

TypeScript Logo

Don't Repeat My Mistakes

Pin Your Shit From Day One

Don't be an idiot like me and wait until everything breaks to pin versions. Start new projects with this in your `package.json` using exact version pinning:

{
  "resolutions": {
    "eslint": "8.57.0",
    "@typescript-eslint/eslint-plugin": "7.18.0",
    "@typescript-eslint/parser": "7.18.0",
    "typescript": "5.5.4"
  },
  "devDependencies": {
    "eslint": "8.57.0",
    "@typescript-eslint/eslint-plugin": "7.18.0"
  }
}

This saves you from the endless cycle of "install new dependency → everything breaks → waste 2 hours trying to figure out what the hell happened."

Bash Script Terminal

The Reality Check Script

I got sick of finding out my dependencies were broken only after trying to run ESLint, so I wrote this bash script to catch this shit early:

#!/bin/bash
## check-deps.sh

echo "Checking if Bun broke anything..."

rm -rf node_modules bun.lockb
bun install 2>&1 | tee /tmp/install.log

if grep -q "incorrect peer dependency" /tmp/install.log; then
    echo "💩 Dependency conflicts found. Fix your resolutions."
    grep "incorrect peer dependency" /tmp/install.log
    exit 1
fi

echo "✅ Dependencies look good"
bunx eslint --version

Run this after any dependency changes. Saved my ass countless times.

Working Version Combinations

After months of trial and error, these tested version combinations actually work with Bun 1.2.21 as of August 2025:

Framework ESLint TypeScript @typescript-eslint/* Notes
React 18 8.57.0 5.5.4 7.18.0 Solid as of Bun 1.2.21
Next.js 14 8.57.0 5.5.4 7.18.0 Works but watch eslint-config-next
Vite 8.57.0 5.5.4 7.18.0 No issues
Node.js 8.57.0 5.5.4 7.18.0 Backend usually fine
Turborepo 8.57.0 5.5.4 7.18.0 Workspace deps still buggy

Just copy these exact versions if you don't want to go through the same hell I did.

Keep npm as Backup

Have a fallback plan because Bun will eventually break something:

{
  "scripts": {
    "install:bun": "bun install",
    "install:npm": "npm install",
    "deps:check": "./check-deps.sh"
  }
}

When Bun updates and suddenly everything's fucked, just run npm run install:npm and get back to actually working.

Save Your Working State

When you find a combination that works, save it:

## Backup your working lockfile
cp bun.lockb bun.lockb.working

## Document what works in your README
echo "# Working Versions" >> README.md
echo "- ESLint: 8.57.0 (DO NOT UPDATE)" >> README.md
echo "- TypeScript: 5.5.4" >> README.md
echo "- Last tested: $(date)" >> README.md

Future you will thank past you when some genius suggests "let's just update everything to the latest versions."

Team Sanity Rules

If you're working with a team, establish some basic rules:

  1. Don't update major dependencies without testing locally first
  2. Pin versions that work, don't chase the latest
  3. If Bun breaks, fall back to npm immediately
  4. Test dependency changes before pushing to main

The time you save not debugging dependency hell is time you can spend building actual features.