Editor’s note: This article was last updated on 23 November 2023 for accuracy since the release of Bun v1.0 and to integrate with Vite, which is preferred for Bun-based React projects.
A JavaScript runtime is an environment that allows you to run JavaScript code and includes the necessary components for JavaScript code execution. It also allows your JavaScript code to interact with the outside world by providing access to core libraries and objects.
Bun is a relatively new and fast all-in-one JavaScript runtime. In this article, we’ll look at some interesting features of Bun, evaluate how it compares to other JavaScript runtimes, and see how to use Bun to bootstrap a React project. Lastly, we’ll run some speed tests to see if Bun is as fast as its website claims!
Bun is a lightweight JavaScript runtime that includes a native bundler, transpiler, task runner, and native npm client. It allows you to bundle, transpile, install, and run JavaScript and TypeScript projects.
Bun is the new kid on the block. It was created by Jared Sumner, released to the public in 2021, and is currently in version v1.0.15.
Bun is all about speed and efficiency and is a strong contender for the top JavaScript runtime spot, claiming to be faster and more feature-rich than Node.js and Deno.
Bun comes with many useful features:
Bun’s website refers to it as a “fast all-in-one JavaScript runtime.” So what else can we do with Bun? Let’s take a look.
Bun’s transpiler is a fantastic feature that converts TypeScript, JSX, and even vanilla JavaScript. Why would you need to transpile plain JavaScript, after all?
That’s a great question. This is where one of Bun’s performance-enhancing features comes into play. Bun automatically optimizes JavaScript before it is executed.
The transpiling feature is still under development, but the developers intend to include an optimized binary format for JavaScript in the future. These optimizations could have significant implications for edge apps and other short-lived processes.
Bun’s task runner is similar to that of Node.js, but it is noticeably faster. You can use Bun’s task manager in a Node project to take advantage of its speed. A task runner is an essential tool — both Node/npm and Deno include one by default.
Furthermore, Bun’s task manager can run almost any script without the need for the run subcommand, whereas npm can only do so for a few script names.
Bun’s package manager outperforms in terms of performance. In fact, Bun should be faster than pnpm or Yarn, and here’s why:
Node.js and Deno are two of the most popular and widely used server-side JavaScript runtime environments. Let’s see how they compare to Bun.
According to benchmarks performed by Bun’s creators, Bun can outperform both Node.js and Deno in I/O-intensive operations such as HTTP servers and SQL:
Bun is built to be faster to start and run than either Node.js or Deno. It also claims to be significantly faster than both server-side JavaScript runtimes due to its use of JavaScriptCore instead of JavaScript V8, its use of Zig for API writing, and extensive tuning and benchmarking.
These claims may appear outlandish — after all, it’s all JavaScript and JavaScript V8 is quite efficient. However, remember when I mentioned Bun’s speed with I/O-intensive tasks? A significant percentage of execution time is spent in the runtime’s API rather than the JavaScript engine itself. Bun is much faster in these cases because it has a faster I/O implementation than either Node.js or Deno.
Bun is not just a JavaScript runtime — it also comes with a host of extra features that make it a versatile and powerful tool for web developers. These features include a bundler, a TypeScript transpiler, and a test runner, which are similar to those found in Deno.
Bun also includes a CSS-in-JS tool, a template builder, and an environment variable loader. Bun does not have the same code weight constraints as web libraries, enabling it to offer both performance optimization and an impressive array of features.
Bun was built to be Node-compatible. It includes full support for CommonJS, Node-API, and some Node.js modules. This feature is extremely useful because it allows you to access the vast Node.js ecosystems.
Now that we have a better understanding of Bun’s many features, let’s see how we can create a React application on the Bun JavaScript runtime.
To start, install Bun on your machine:
curl https://bun.sh/install | bash
Use the following command to check that Bun was successfully installed:
bun -v
Now, let’s install React.
There are several ways to start a React project — using Create React App, Vite, or even piecing it all together from scratch. While Bun allows you to bootstrap your application with starter templates like the ones we’ve mentioned, Vite is the preferred option, not only because it was designed to be fast, but also because it benefits from Bun optimization and speed magic.
To start a React app with Bun and Vite, run:
bun vite
Notice that it took 8.28 seconds to set up React with Bun and Vite.
While you can use Bun to bootstrap a CRA template, it doesn’t come with the Bun performance benefits or setup. It would be a better option to use npx as shown below:
npx create-react-app my-app
Let’s try it out. Run the command below on your terminal in the directory you want your React application to live:
bun create react-app name
The result should look like the one below:
It took an entire three minutes to set up React with Create React App and Bun.
Let’s take a closer look at the generated files, starting with the one generated with Vite:
Notice that the generated files have Bun’s bun.lockb
file. This file is equivalent to the package-lock.json
file in for Node.js but it’s a binary file. This implies that Vite used Bun to set up React to benefit from its speed.
Below is an image that shows the generated files after bootstrapping a React app via Create React App:
And behold, it didn’t use Bun to install the packages. How did we know that? Because there is no bun.lockb
file.
In the following section, we’ll see how to fully integrate Bun into your React app using Vite as a case study.
Integrating Bun into your React app mainly consists of two steps:
1. Removing lock files and regenerating them:
Deleting your current lock file, e.g., package-lock.json
, yarn.lock
, or pnpm.lock
and running bun install
to generate the bun.ockb
file will prepare your React application for Bun adoption.
2. Updating script runner in package.json:
Modify the script runner in your package.json
file to use Bun as the runtime environment for your React app as shown below:
//.. "scripts": { "dev": "bunx --bun vite", "build": "vite build", "serve": "vite preview" }, // ...
Notice that we used bunx --bun
. For now, that’s how you invoke the Bun runtime because Vite build tools and Create React App don’t default to the Bun runtime. This may change in the future.
Now you can run bun dev
on your terminal and it will run your React dev server with Bun.
Let’s perform a simple speed test to see whether Bun or Node executes code the fastest. Our program is just a simple loop — at the start of the program, we start a timer and when the loop finishes its iteration, we end the timer.
Here’s the code for the program:
console.time('test'); for (let i = 0; i < 10000; i++) console.log(i) console.timeEnd("test");
Let’s run our speed test:
bun-test.js
To run the program with Bun, use this command:
bun [file name]
Here’s the result from running the program with Bun:
It took Bun 22.39ms to complete the loop. Now, let’s see how long it will take Node.js to complete the same program.
To run the program with Node, use this command:
node [file name]
Here’s the result from running the program with Node:
It took Node 163.225ms to complete the same program!
Bun is many things, including a test runner. Its test runner is fast and compatible with Jest. That means if you are looking to migrate your test from Jest, you won’t need to rewrite your test suits.
But there are a few caveats you should take note of while working with Bun test. The first is that Bun doesn’t support JSDOM out of the box. Instead, it works with Happy DOM and requires additional setup for it to work.
You’ll need to complete the following steps to get it to work. First, you’ll need to install JSDOM and register it to work with Bun via the config bunfig.toml
file, the config file for Bun:
[test] preload = "./happydom.ts"
To register it, you need to install the Happy DOM Global Registration library:
bun add @happy-dom/global-registrator
Now, create a happydom.ts
file in the root directory and add the following code into it to register it:
import { GlobalRegistrator } from "@happy-dom/global-registrator"; GlobalRegistrator.register();
And that’s all there is to it! If your tests use TypeScript, then you need one more configuration — you need to install bun-types
and add it to the tsconfig.json
file.
Here is an example test case. You will have to import all the test functions from 'bun:test'
as shown in the code below:
// counter.test.tsx import { fireEvent, render, screen, waitFor } from '@testing-library/react' import App from './App' import { describe, expect, test } from 'bun:test' describe('App', () => { test('counter increments when button is clicked', async () => { render(<App />) const button = screen.getByText('count is 0'); fireEvent.click(button); await waitFor(() => { expect(screen.getByText('count is 1')).toBeTruthy() }); }); });
Finally, you can run your test suits and the result will look like this:
In this article, we took an in-depth look at Bun’s features and compared them to other popular JavaScript runtimes, such as Node.js and Deno.
We also demonstrated how to create a simple React app with Bun, and ran tests to show just how fast and efficient Bun is compared to other runtimes. Because Bun is in its early stage, there is a chance that you’ll face some issues with integrating some libraries. If you discover a bug, please open an issue in the GitHub repository.
Additionally, the project’s development is progressing rapidly, so always verify the version you are using as your initial troubleshooting step. If you are in an older version, the issue you are facing might have been fixed in the latest version — you can run bun upgrade --canary
to update to the latest version.
Happy hacking!
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowMatcha, a famous green tea, is known for its stress-reducing benefits. I wouldn’t claim that this tea necessarily inspired the […]
Backdrop and background have similar meanings, as they both refer to the area behind something. The main difference is that […]
AI tools like IBM API Connect and Postbot can streamline writing and executing API tests and guard against AI hallucinations or other complications.
Explore DOM manipulation patterns in JavaScript, such as choosing the right querySelector, caching elements, improving event handling, and more.