Summary
- 🐇 Bun is super fast –
bun install
is way quicker than npm, pnpm, or yarn (up to 17× faster!). - ⚡ Old bottlenecks are gone – today’s SSDs and fast internet mean system calls (asking the OS for stuff) are the new slowdown.
- 🔧 Less talking to the OS – Bun makes fewer syscalls (like 165k vs millions for others). That saves tons of time.
- 🛠 Built in Zig – a low-level programming language lets Bun talk directly to the OS, skipping Node’s slow middle layers.
- 📦 Smart caching – Bun saves package info in a compact binary format. No need to re-parse big JSON files every time.
- 🎁 Better untar & unzip – uses
libdeflate
and pre-sizes memory so unzipping is faster and smoother. - 🧩 Memory done right – instead of scattered data, Bun arranges info neatly (cache-friendly) so the CPU zips through it faster.
- 📂 Clever file copying – uses OS tricks like clonefile (macOS) and hardlinks (Linux) to copy files instantly without waste.
- 🏎 Multi-core power – Bun spreads work across all CPU cores without slowdown from thread fights.
- 🎉 End result – installs that used to take seconds (or minutes) now finish in milliseconds.
Bun’s bun install
is designed to be dramatically faster than existing JavaScript package managers by treating package installation as a systems-programming problem rather than as a JavaScript problem. The Bun team reports average speedups of roughly 7× vs npm, 4× vs pnpm, and 17× vs yarn, and backs those claims with syscall and timing traces showing far fewer expensive system calls during installs. (Bun)
Original Blog: https://bun.com/blog/behind-the-scenes-of-bun-install
Why does this matter? Historically, tools like Node.js were optimized for an era where I/O (disk and network) was the primary bottleneck. Node’s event loop and libuv thread pool were excellent for hiding long waits on slow disks or remote APIs. But hardware has changed: modern SSDs, fast networks, and multi-core CPUs mean the old bottlenecks disappeared and system call overhead and poor memory/cache layout became the new limits. Every system call requires switching the CPU from user mode to kernel mode, which costs hundreds to a few thousand CPU cycles — enough to dominate an install that makes tens of thousands (or millions) of syscalls.
Bun’s measurements tell the story: in their strace comparisons, bun made far fewer syscalls (e.g., ~165k) than npm (~997k), pnpm (~457k) or yarn (~4M), and finished installs several times faster. They also note that many Node-based tools generate lots of futex
calls (thread waits), which indicate contention and idle time inside thread pools — another source of slowdown. These concrete syscall counts and timings are central to Bun’s argument that minimizing syscalls and thread contention yields big wins. (Bun)
The technical approach: Bun is written in Zig, a compiled language that can make direct system calls. That eliminates the JavaScript → libuv → thread pool → kernel pipeline and the repeated argument validation, string conversions, and cross-runtime messaging that add overhead for each file operation. With direct syscalls Bun reads files and performs kernel work with fewer intermediate layers, which yields much higher raw throughput of file operations (their internal test shows Bun processing many more package.json
files per second than Node.js). (Bun)
Beyond removing layers, Bun applies many low-level optimizations across the whole install pipeline. It caches package manifests in a compact binary format so repeated installs avoid JSON parsing and duplicate string allocations; this makes cached installs extremely fast. For tarball extraction, Bun buffers entire compressed files (most npm packages are small) and reads the gzip footer to pre-allocate the exact decompressed size, avoiding repeated buffer growth and copies, and it uses libdeflate
for faster decompression. These micro-optimizations together cut both CPU work and memory churn. (Bun)
Bun also redesigns in-memory data layout to be cache-friendly. Instead of many scattered JavaScript objects, it uses a Structure-of-Arrays layout: large contiguous buffers for package metadata, dependency lists, and strings. This improves CPU cache locality and reduces pointer-chasing, so traversing thousands of dependencies becomes far cheaper in CPU cycles. The lockfile format follows the same idea to avoid heavy JSON parsing and allocations. (Bun)
File copying — the part that often produces the most syscalls — is optimized by using OS-specific features. On macOS Bun uses clonefile()
(copy-on-write) so entire trees can be cloned with a single syscall; on Linux it prefers hardlinks, then ioctl-based reflinks, copy_file_range
, sendfile
, and only falls back to traditional read/write copying when necessary. These approaches keep data movement inside the kernel and avoid repeated user↔kernel mode switches. Benchmarks show the copy-on-write or hardlink backends are several times faster than naive copying. (Bun)
Finally, Bun leverages multi-core CPUs with a lock-free, work-stealing thread pool plus dedicated network threads and per-thread memory pools. That lets the installer use many cores in parallel without the heavy futex
contention that plagues naive multi-threaded designs. The result: far better CPU utilization and much shorter wall-clock times for real projects. (Bun)
In short: Bun’s speed comes from rethinking the whole stack — avoid repeated syscalls, use native OS primitives for copying, cache and store manifests compactly, optimize decompression, and use cache-friendly in-memory layouts and real multicore scheduling. These are engineering choices aimed at modern hardware, and Bun shows that when you eliminate historical layers of overhead, package installation can go from many seconds or minutes down to (milli)seconds for common cases. (Bun)
📌 Read Our Latest Posts:
Leave a Reply