Why We Chose Bun Over Node.js for AccessAgent
We built AccessAgent's backend on Bun instead of Node.js. Here's why — startup time, native TypeScript, and a dramatically simpler toolchain.
When we started building AccessAgent’s backend, we had a genuine choice to make: Node.js (the safe, well-tested default) or Bun (the newer, faster runtime).
We chose Bun. Here’s the reasoning.
What Bun actually is
Bun is a JavaScript/TypeScript runtime, package manager, bundler, and test runner — all in one binary. Where Node.js is the runtime and you reach for npm/yarn, esbuild, jest, and tsx separately, Bun replaces all of them.
It runs on JavaScriptCore (the engine Safari uses) rather than V8, which contributes to its speed. And it’s designed to be a drop-in replacement for Node.js — most npm packages work without modification.
The performance argument
The raw numbers are real. Bun starts faster, handles HTTP requests faster, and does I/O faster than Node.js in most benchmarks. For AccessAgent specifically:
Startup time matters. When a user creates a project and triggers the agent, we’re spinning up processing that needs to respond quickly. Bun’s cold start time is meaningfully lower.
Package installation. bun install is dramatically faster than npm install. In CI, this adds up. In development, it’s the difference between 30 seconds and 5 seconds on a fresh install.
TypeScript natively. This was actually the most impactful reason for us.
Native TypeScript support
With Node.js, TypeScript requires a build step or a loader like ts-node or tsx. You either compile TypeScript to JavaScript before running, or you use a JIT transpiler. Either way, there’s overhead and configuration.
Bun runs TypeScript files directly. No tsconfig.json required to just run a file. No build step in development. You write bun src/server/index.ts and it runs.
For a project that is TypeScript-all-the-way-down — no JavaScript files, no Python, no exceptions — this is a meaningful simplification.
A simpler toolchain
AccessAgent’s core/ package uses:
- Bun as the runtime
- Bun’s built-in test runner for tests
- Bun’s built-in bundler for building
bun installfor dependencies
That’s it. No Jest config. No Webpack or Vite config for the server. No ts-node or tsx. No separate npm run build step that produces files you then run with node.
When you’re trying to keep self-hosting as simple as possible — and one of our goals is git clone && bun install && bun dev as the complete setup — reducing moving parts matters.
The one caveat
Bun’s Node.js compatibility is very good but not perfect. A small number of npm packages use Node.js APIs that Bun doesn’t fully support. We’ve hit this exactly twice in AccessAgent’s development, both times finding a drop-in alternative that was better anyway.
If you’re building on top of existing Node.js code with unusual dependencies, test Bun compatibility before committing. For greenfield TypeScript projects, it’s a safe choice.
Would we choose Bun again?
Yes. The developer experience improvement is real — faster installs, native TypeScript, one binary for everything. The performance gains are meaningful but not our primary reason. The toolchain simplification is.
For a project that self-hosters need to install and run in 5 minutes, simpler is better. Bun delivers that.