AI 소식10 min

I Tried Bun 2.0 — Why I Ditched npm for Good

I ran Bun 2.0 through everything — installation, bundler, test runner, and package management. Here's how much faster it actually is compared to npm, what to watch out for when migrating existing projects, and the settings you can apply to real work right away.

April 2026 · GoCodeLab

The JavaScript development ecosystem is full of tools. Package managers, bundlers, transpilers, and test runners all exist as separate pieces. Each has its own config file, and versions need to be managed independently. Starting a new project means repeating this setup every single time — and somehow that became normal.

Bun collapses all four into a single binary. Runtime, package manager, bundler, and test runner are all packed into one bun command. Install it and you can immediately run TypeScript, install packages, build, and run tests. One tool instead of four.

I ran it myself. On a monorepo cold install, npm took 134.2 seconds. Bun took 4.8 seconds. That's a 28x difference. The number alone didn't sink in — but after feeling it firsthand, going back to npm felt uncomfortable.

Quick Summary
- Package installation: up to 28x faster than npm (monorepo baseline)
- Testing: 11x faster than Jest (1,500 cases: 44s → 4s)
- Bundler: HTML file as entry point. Supports single-file builds
- DB: PostgreSQL, MySQL, MariaDB, SQLite built-in. No separate driver needed
- Node.js compatibility ~98%

What is Bun

Bun is a JavaScript runtime created by Jarred Sumner. Unlike Node.js, which runs on the V8 engine (the Chrome engine), Bun is built on Apple's JavaScriptCore — the same engine Safari uses. On top of that, the entire runtime was rewritten in Zig. Zig delivers C-level performance with direct memory control. It was a deliberate choice to squeeze out maximum speed.

The core design principle is one thing: consolidate tools. bun alone handles package installation instead of npm, bundling instead of esbuild/webpack, testing instead of Jest, and TypeScript execution instead of ts-node. Fewer packages to install, fewer config files to manage.

Node.js compatibility was a priority from the start. Major packages like Express, Fastify, and Prisma work without modification. v1.0 launched in September 2023. v1.2 added a built-in DB client. v1.3 completed MySQL/MariaDB support and the HTML entry point bundler.

Installation — one command to start

macOS and Linux are done in one line. Windows works with a single PowerShell command. After installation, run bun --version to confirm it's working.

# macOS / Linux
curl -fsSL https://bun.sh/install | bash

# Windows (PowerShell)
powershell -c "irm bun.sh/install.ps1 | iex"

# Verify version
bun --version

TypeScript runs immediately with no extra configuration. Type bun run index.ts and it works without transpilation. No need to install ts-node or tsx separately. Same goes for JSX — .tsx files run directly.

It coexists with existing Node.js projects. Using different runtimes per project causes no conflicts. You can use node in one directory and bun in another without issues. If switching feels risky, starting with just the package manager is a valid first step.

Package management — the difference is tangible

The speed gap comes from system call count. npm makes around 1 million system calls during package installation. Bun makes 165,000. The file I/O handled is fundamentally different. That difference produces the result: 134.2 seconds vs. 4.8 seconds on a monorepo baseline. In CI pipelines that install dependencies on every build, the cumulative effect is significant.

MetricnpmpnpmBun
Monorepo cold install134.2s15s4.8s
React app dependencies18s2s
Tests (1,500 cases)44s (Jest)4s
Built-in DB clientXXO

The lockfile is bun.lockb — a binary format by default. Being binary makes it inconvenient to read with git diff. If you need a text format, you can switch to bun.lock via bunfig.toml. Either format must be committed to git to pin versions.

The commands are nearly identical to npm. bun add lodash, bun remove lodash, and bun update all work the same way. In CI pipelines, use bun install --frozen-lockfile to install strictly from the lockfile — the equivalent of npm ci.

Bundling — HTML is the entry point

Bun's built-in bundler is esbuild-based. No need to write a separate Webpack config file. A single bun build command handles JS, CSS, and assets in one pass. Configuration complexity is drastically reduced compared to existing bundlers.

The standout feature is that HTML serves as the entry point. Running bun build ./index.html --outdir=dist automatically detects <script> and <link> tags in the HTML. JS, CSS, and image assets are all processed in one shot. No need to specify a separate JS entry point the way Webpack requires.

Adding the --compile flag produces a single executable with all assets inlined. From v1.3, HTML imports come with HMR (Hot Module Replacement) and React Fast Refresh. Pass an HTML file to Bun.serve() and that becomes your dev server. No separate dev server process to spin up.

# Production bundle
bun build ./index.html --outdir=dist

# Single executable build
bun build ./index.html --outdir=dist --compile

# Dev server (with HMR, Bun.serve-based)
bun run dev

Test runner — uses the Jest API as-is

bun test provides a Jest-compatible API. describe, test, expect, beforeEach, and afterAll all work. No need to write a jest.config.js — just run bun test. If you were using Jest before, no test files need to be modified.

The speed difference is substantial. With 1,500 test cases, Jest takes 44 seconds. Bun takes 4 seconds. That's 11x faster. On projects with a large test suite, the time saved during local verification before a git push adds up fast. If you use TDD or keep watch mode running, the impact is even more noticeable.

A fake timers compatibility bug with @testing-library/react was fixed in v1.3.5. However, some items like expect.arrayContaining are still not implemented. Before fully migrating an existing Jest project, it's safer to run bun test once and check the results.

# Run all tests
bun test

# Run a specific file
bun test src/utils.test.ts

# Watch mode
bun test --watch

Built-in DB client — no driver needed

Since v1.2, PostgreSQL and SQLite clients have been built into the runtime. No need to install pg or better-sqlite3. v1.3 added MySQL and MariaDB support, consolidating everything into the single Bun.SQL API. You can connect directly to a DB without any external driver.

Bun.SQL identifies the database from the connection string. It recognizes postgres://, mysql://, and file:./db.sqlite formats. Swap the connection string and the query code stays the same even when switching databases. No more learning different client APIs for each DB.

// PostgreSQL connection
const db = new Bun.SQL("postgres://user:pass@localhost/mydb");

// Template literal → automatic parameter binding
const userId = 42;
const result = await db`SELECT * FROM users WHERE id = ${userId}`;

// SQLite (just a different path)
const sqlite = new Bun.SQL("./mydb.sqlite");
SQL injection prevention built-in
Writing queries with template literals automatically binds values as parameters. Even when you write ${userId}, the string is never inserted directly into the query. Injection is blocked without any separate escaping.

Migrating from Node.js

A gradual migration is the realistic approach. There is no need to switch everything at once. Replace tools one at a time: package manager → test runner → bundler. If a problem comes up at any step, stop there.

Node.js toolBun commandNotes
npm installbun installLockfile format differs
npx ts-node file.tsbun run file.tsNo transpilation needed
jestbun testCheck for unimplemented items
webpack / esbuildbun buildHTML as entry point
pg / mysql2Bun.SQLv1.2+, no install needed
better-sqlite3Bun.SQLv1.2+

The first step is replacing the package manager. Run bun install in the folder containing package.json. node_modules gets rebuilt and bun.lockb is created. No code changes required whatsoever. This alone changes CI pipeline times.

Node.js compatibility ~98%
Most packages on npm work in Bun without modification. Express, Fastify, Prisma, Drizzle, and tRPC have all been confirmed. The only cases that don't work are packages using C++ bindings (native addons). Before migrating, you can quickly verify with bun install && bun run start.

Decision criteria by use case

Where Bun makes sense depends on the project situation. For new projects, starting with Bun from scratch is the most straightforward path. For existing projects, gradual migration is realistic. CI/CD pipelines are the entry point where you'll see the fastest payoff.

SituationRecommendationReason
New projectStrongly recommendedMinimal tooling setup, start immediately with no config files
CI/CD pipelineRecommendedImprove package install speed with zero code changes
Existing npm projectGradual migrationReplace package manager first, expand incrementally
Native addon usageVerify firstSome C++ binding packages are incompatible
Enterprise productionValidate before adoptingEcosystem maturity gap compared to Node.js

Swapping npm install for bun install in CI/CD carries the lowest risk. The code stays untouched. Only build time shrinks. Running it in the pipeline first before the entire team switches to Bun is also a valid approach.

Limitations and caveats

Bun is still maturing. Node.js has been battle-tested in production for over 15 years. The depth of the ecosystem and the size of the community are significantly different. Native addons — packages using C++ bindings — may not work. It's safer to check your package list before migrating.

Windows support has stabilized compared to early v1.x. PowerShell installation is now supported, but real-world validation cases are fewer than on macOS and Linux. If your team has many Windows development environments, test thoroughly before adopting.

For enterprise production environments, sufficient validation is needed before adoption. The realistic approach is to use it on personal or side projects first, then expand to team projects. There is no need to adopt all of Bun at once. Using only the package manager and keeping everything else as-is is also a perfectly valid choice.

Pre-migration checklist
1. Check whether the project uses any native addon packages
2. After bun install, verify basic behavior with bun run start
3. If existing tests are in place, run them once with bun test
4. Commit bun.lockb to git

There is no need to adopt all of Bun at once. Swapping the package manager first, then the test runner, then the bundler — migrating one piece at a time is a valid path. If each step has no issues, move on to the next.

FAQ

Q. Can Bun fully replace Node.js?

npm package compatibility is around 98%. Major packages like Express, Fastify, and Prisma work without modification. Only packages using native addons (C++ bindings) need separate verification. Most projects work as-is.

Q. Does bun test fully replace Jest?

Most of the API is compatible. describe, test, expect, and mock functions all work. However, some items like expect.arrayContaining are still not implemented. It is safer to run existing tests once before migrating everything over.

Q. Why does the bun.lockb file need to be committed to git?

bun.lockb is a binary lockfile. Without it, package versions are not pinned. Different team members may end up with different versions installed. If you need a text format, you can switch to bun.lock.

Q. Which databases does Bun SQL support?

As of v1.3, PostgreSQL, MySQL, MariaDB, and SQLite are all handled through the single Bun.SQL API. No separate npm driver installation is needed. Swap the connection string and the query code stays the same even after switching databases.

Q. What is the easiest way to switch from an existing npm project to Bun?

Just run bun install in the directory that has a package.json. No code changes needed. Swapping the package manager first to feel the speed difference is the safest entry point. This alone changes CI pipeline times.

There is no need to adopt all of Bun at once. Swapping the package manager first, then the test runner, then the bundler — gradual migration is entirely possible. If you are currently using npm install in CI, switching to bun install today is enough of a start.

Official sources
- Bun official blog — v1.2, v1.3 release notes
- Bun official docs — installation, API, bundler, test runner
- oven-sh/bun GitHub — source code and issue tracker

Get GoCodeLab Updates

JavaScript, AI tools, and developer productivity insights — personally verified before sharing.

Subscribe

The figures in this article are based on official Bun release notes and benchmark data. Actual performance may vary depending on the environment.

Last updated: April 2026 · GoCodeLab