Bun is an all-in-one JavaScript runtime and toolkit created with the explicit goals of serving as a drop-in replacement for Node.js, eliminating separate layers of tooling, and speeding up the development experience. In this article, we look at how Bun works under the hood and how to start using it in your projects.
Bun reached a major milestone on September 8, 2023 with the release of version 1.0, marking the first “production-ready” release for Bun’s macOS and Linux builds. The Windows build, however, is still experimental, with only the JavaScript runtime supported. The package manager, test runner, and bundler included in the macOS and Linux builds of Bun are disabled in the Windows version. The plan is to include them once they’re more stable and their performance has been optimized.
Compatibility With Node.js
Bun’s goal may be to serve as a “drop-in replacement for Node.js,” but that compatibility is still a work in progress. Bun uses the same module resolution algorithm as Node.js, with many built-in and global modules fully supported. However, others are only partially implemented, and a number aren’t implemented at all. Prominent Node.js contributor Matteo Collima noted this in a generally positive article about Bun, writing “In my experience, it’s not a drop-in replacement, and many inner details differ. This results in many random issues over my repos asking for fixes for Bun incompatibilities while people try it out…Ultimately, Bun does not implement all Node.js APIs. It’s not a clean drop-in replacement for Node.js (despite their claims).”
The Bun team regularly updates the compatibility page as support is improved. Make sure to read up on the latest details there before deciding if Bun will meet the needs of a project currently using Node.js.
How Does Bun Stack Up?
Some of Bun’s major selling points are its speed compared to competitors like Node.js and Deno, an improved developer experience by combining features into a cohesive toolkit, support for modern JavaScript features like top-level await, classes, and optional chaining without the need for transpilation. Let’s take a look at how it stacks up.
- Faster performance: Bun uses the JavaScriptCore (JSC) engine for its runtime, as opposed to Node.js and Deno, which use V8. There are always tradeoffs and different optimization strategies when it comes to performance. In general, JSC makes faster start times and low memory usage as top priorities. V8, on the other hand, prioritizes faster execution with more runtime optimization.
None of that actually answers the question: Is Bun faster? The answer appears to be “Yes!” at least in basic “hello world” scenarios. The test results at that link clock Bun’s native server at twice the speed of Node.js, and 1.5 times the speed of Deno.
- Developer experience: One of the ideas behind Bun was to combine a package manager, bundler, and test runner into a cohesive toolkit for building apps, eliminating the many layers of tooling used by Node.js. It’s an attractive notion, but the execution is not without its critics.
In Bun Hype: How We Learned Nothing From Yarn, Jared Wilcurt argues “Bun is just an abstraction layer on top of the tools we already have. Meaning it will always be behind the curve and can introduce additional bugs at that layer. Not ideal for such mission critical systems like installing dependencies, testing code, and building the code to be sent to production.”
- Transpilation: Most runtimes require a separate build step to transpile source code before executing it. Bun handles transpilation source code automatically at runtime. We’ll look at this a little deeper in the next section.
How Bun Handles Transpilation
A key difference between Bun and other JavaScript runtimes is its approach to transpilation, the process of converting source code to another language or a different version of the same language.
Bun transpiles source code automatically at runtime, eliminating the need for a separate build process. For example, TypeScript and JSX files can be executed directly:
// index.tsx
const element = <h1>Hello World!</h1>
console.log(element)
Bun will convert the TypeScript and JSX to plain JavaScript when executing this file.
No Intermediate Output
With Bun, transpiled JavaScript is never written to disk. It transpiles source to an in-memory intermediate representation. This avoids potential confusion around intermediate build artifacts. The source files are the only definitive representation of the code.
Intelligent Caching
To avoid re-transpiling unchanged modules, Bun intelligently caches transpiled module outputs. The cache is invalidated when source files change.
Installing Bun
There are a few different ways to install Bun, including with cURL
on macOS, Linux, and WSL:
curl -fsSL https://bun.sh/install | bash
Bun’s installation page also includes instructions for installing the runtime through npm, Docker, Homebrew, and Proto.
Alternatively, you can download the binaries for Bun directly from the the releases page. Make sure to select the appropriate file for your operating system and CPU architecture.
Using Bun
The bun
command is the starting point, providing subcommands for running code, bundling projects, executing tests, and more:
bun run
: Run JavaScript/TypeScript code.bun build
: Bundle for production.bun test
: Run tests with Jest-style API.bun install
: Install dependencies.bun init
: Scaffolds a new project through an interactive tool.
Installing Dependencies
Bun uses the same package.json
workflow as Node.js to install dependencies, with the command bun install used to install all dependencies on a project. To install a particular package, you’d use bun add
, followed by the name of the package. Packages are stored in a global cache, with subdirectory names indicating both the package name and version. This allows you to cache multiple versions of the same package. Imported packages are installed on the fly during execution.
Getting Started With Bun
Bun has a lengthy list of code examples and guides to get you started. We suggest following the Quickstart to create a simple HTTP server and get a feel for how Bun works. From there, you can move on to importing JSON and TOML files, run tests in watch mode, and use React and JSX.
Wrapping Up
It’s natural to see a lot of hype surrounding any shiny new tool, and that’s the position Bun is in right now. Time will tell if Bun lives up to the hype, and truly becomes the drop-in replacement for Node.js it’s been touted to be.
Have you used Bun, either on a project or for educational purposes? Do you think it will be around for the long haul, or more of a flash in the pan? Let us know in the comments.