DEV Community

Cover image for Bun: The JavaScript runtime taking on Node.js and Deno
Matt Angelosanto for LogRocket

Posted on • Originally published at blog.logrocket.com

Bun: The JavaScript runtime taking on Node.js and Deno

Written by Alex Merced✏️

Bun is a new, blazing fast JavaScript runtime that has everyone talking. To understand why Bun is such a big deal, let’s first review some important JavaScript history.

What is a JavaScript engine?

When JavaScript was first created, it only ran in browsers, originally Netscape Navigator. However, developers needed software that could read JavaScript code and turn it into something that could run on the computer. This technology is known as the JavaScript engine. At the time of writing, there are three main JavaScript engines that power your favorite browsers:

  • V8: Created by Google for Chrome
  • SpinderMonkey: Created by Mozilla for Firefox
  • JavaScriptCore: Created by Apple for Safari

Each JavaScript engine has its own minor differences in its support for the JavaScript spec, how quickly it adopts new JavaScript features, and its ease of use and performance.

Introducing JavaScript runtimes

Eventually, in 2009, Ryan Dahl first began to develop a tool that would allow JavaScript to run outside of the browser. When choosing an engine to build this tool around, he chose V8.

What he created was a JavaScript runtime, a tool for running JavaScript outside of the browser. It gave JavaScript access to your broader computer network and file systems for creating web servers and any type of application you can think of.

Node.js has since exploded in popularity, becoming a go-to tool in frontend and backend web development. When Node.js was created, many modern JavaScript standards didn’t exist yet, like the Fetch API, ES modules, and more.

Seeing the growth of TypeScript and the robustness of web standards, Ryan Dahl created a successor to Node.js using Rust, called Deno. Deno offered speed improvement, an embrace of web standards, and first class support of TypeScript and JSX.

What is Bun?

In 2022, former Stripe developer Jared Sumner released Bun. Bun is a runtime developed in the Zig programming language, which also embraces web standards but aims for compatibility with Node.js APIs, so developers can easily migrate existing code.

One of the most interesting choices is that Bun uses the JavaScriptCore as its engine, unlike Node.js and Deno, which use V8. The result is a blazing fast runtime that also offers several quality of life features for JavaScript developers.

Bun also has first class integration of TypeScript and JSX. It aims to provide many of the features of transpilers, like Babel, and Bundlers like Webpack, Rollup, Snowpack, and Vite.

Taking Bun for a test drive

To get started with Bun, first, we’ll have to install it. According to the Bun documentation, installation requires only the following command:

curl https://bun.sh/install | bash
Enter fullscreen mode Exit fullscreen mode

Keep in mind, this command will only work on Mac and Linux. So, if you’re using Windows, you’ll need to set up Window Subsystem for Linux to install Bun.

Once it’s done installing, make sure to read the confirmation prompt with directions for adding Bun to your PATH. It will require you to add the following lines to your .bashrc or .zshrc files:

BUN_INSTALL="/home/<username>/.bun"
PATH="$BUN_INSTALL/bin:$PATH"
Enter fullscreen mode Exit fullscreen mode

Now, if you run bun--version, you should get a version number printed confirming you have installed it correctly.

Writing and running our first Bun script

Create a file called script.js and add the following code inside it:

Bun.serve({
    fetch(request){
        return new Response("Hello World")
    }
})
console.log("Listening on Port 3000")
Enter fullscreen mode Exit fullscreen mode

Bun.serve initiates the server and takes an object with the server configurations. On each request, the request object is passed to a function stored as the fetch property on the configuration object.

We can run Bun.serve by using the command bun run script.js and then going to localhost:3000 to see the response to our request. If we wanted to change which port it will serve on, we can add a port property to the object passed to Bun.serve.

Writing files with Bun

Bun has a pretty simple API for writing to files. Let’s modify our script to write to a file each time we submit a request:

let count = 1
Bun.serve({
    fetch(request){
        Bun.write(`${count}.txt`, request.url)
        count += 1
        return new Response("Hello World")
    },
})
console.log("Listening on Port 3000")
Enter fullscreen mode Exit fullscreen mode

Run the code above and visit localhost:3000/cheese, and you’ll see two new files created, 1.txt and 2.txt. The first argument of Bun.write is the target of the write, like a file or stdout, and the second argument is what to write.

Built in support for SQLite3

Unlike other JavaScript runtimes, you don’t have to install SQLite3 because it’s built in out of the box. Let’s create a new file called db.js with the following code:

import { Database } from "bun:sqlite";
// Create a new Database File
const db = new Database("db.sqlite3");
// Create a table in the database
db.run("CREATE TABLE IF NOT EXISTS cheeses (name VARCHAR(100));")
// Insert Some Values into the table
db.run("INSERT INTO cheeses VALUES ('gouda'), ('munster'), ('brie');")
// Query the table
const result = db.query("SELECT * FROM cheeses;").all()
// Log results
console.log(result)
Enter fullscreen mode Exit fullscreen mode

Run the code with bun run db.js, and you should see the records that are inserted logged on the terminal.

Using .env files with Bun

Another really nice touch is the ability to use .env files out of the box. You can simply access them with process.env like in Node.js without needing to install any libraries. Create an .env file with the following command:

VARIABLE=cheddar
Enter fullscreen mode Exit fullscreen mode

Now, let’s update our script.js with the following code:

// let count = 1
Bun.serve({
    fetch(request){
        // Bun.write(`${count}.txt`, request.url)
        // count += 1
        return new Response(process.env.VARIABLE)
    },
})
console.log("Listening on Port 3000")
Enter fullscreen mode Exit fullscreen mode

Now, when we run bun run script.js and visit localhost:3000, we should should see the information from our .env file being returned.

Conclusion

Beyond being super fast, Bun has some very nice features that make many of the more mundane tasks like writing files, managing simple databases, and using environmental variables quite easy.

Will Bun overtake Deno and challenge Node.js for its throne? We’ll have to wait and see. Bun will at least, like Deno, show off many innovations that Node.js can adopt while carving out a space of its own.

Either way, it’s a big win for JavaScript developers everywhere to have another runtime in the space. At the time of writing, Bun is still early in its development with many APIs and features not yet implemented. However, what is available so far is quite impressive, so it’s worth keeping up with.

Be sure to check out this video of my first test run of Bun and leave a comment if you have any questions. Happy coding!


200’s only ✔️ Monitor failed and slow network requests in production

Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third party services are successful, try LogRocket.

LogRocket Sign Up

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens while a user interacts with your app. Instead of guessing why problems happen, you can aggregate and report on problematic network requests to quickly understand the root cause.

Top comments (0)