Saya pertama kali coba Bun karena kesel sama setup Node.js yang ribet. Install dependency lambat, TypeScript butuh tsc plus nodemon plus ts-node, dan semuanya makan waktu sebelum saya bisa nulis satu baris kode pun. Bun janji satu tool buat gantiin semuanya: runtime, package manager, bundler, sampai test runner. Ternyata janjinya beneran kepakai di kerjaan sehari-hari.

Install Bun di Linux, macOS, dan Windows

Bun support tiga OS utama. Di Linux dan macOS tinggal jalankan satu baris curl, sementara Windows pakai PowerShell. Prosesnya cepat karena binary-nya diunduh sebagai satu file tanpa dependency tambahan.

bash
curl -fsSL https://bun.sh/install | bash

Setelah selesai, tutup lalu buka lagi terminal dan cek versinya. Kalau perintah di bawah mengembalikan nomor versi, berarti install-nya sukses.

bash
bun --version

Di Windows, buka PowerShell dan jalankan installer resminya lewat irm bun.sh/install.ps1 | iex. Kalau kamu lebih nyaman pakai WSL, perintah curl di atas juga jalan di dalam terminal WSL.

Menjalankan TypeScript tanpa build step

Ini fitur yang bikin saya pindah. Bun membaca TypeScript langsung tanpa perlu tsc, ts-node, atau konfigurasi apa pun. Buat file bernama hello.ts dengan isi berikut.

typescript
// hello.ts
export function sapa(nama: string): string {
  return `Halo, ${nama}!`;
}

console.log(sapa("BengkelKode"));

Lalu jalankan dengan bun hello.ts. Tidak ada step kompilasi, tidak ada file .js hasil build yang menumpuk. Bun membuang type annotation dan langsung mengeksekusi JavaScript-nya. Pengecekan tipe tetap jalan di editor lewat TypeScript, tapi Bun tidak pernah mengulur waktu kamu dengan proses build.

Kalau kamu butuh pengecekan tipe sebelum deploy, jalankan bunx tsc --noEmit. Bun memanggil TypeScript lewat bunx tanpa perlu install global.

Scaffold project dengan bun init

Buat folder baru dan jalankan bun init. Perintah ini membuat package.json, tsconfig.json, index.ts, dan .gitignore sekaligus — versi Bun yang lebih rapi dari npm init.

bash
mkdir todo-api && cd todo-api
bun init

Package manager: bun add, bun install, dan bun.lock

Bun menyertakan package manager yang kompatibel dengan registry npm. Untuk API di bawah kamu tidak perlu install apa pun, karena server HTTP dan database SQLite sudah bawaan Bun. Tapi biar lengkap, begini cara menambah dependency biasa dan dependency khusus development.

bash
bun add zod
bun add -d @types/node

bun add menulis dependency ke package.json sekaligus memperbarui bun.lock. Flag -d menandai package sebagai devDependency. Kalau kamu kloning project yang sudah punya bun.lock, cukup jalankan bun install dan Bun membaca lockfile itu untuk mereplikasi versi persis yang sama di semua mesin.

Test runner bawaan dengan bun:test

Bun punya test runner sendiri yang sintaksnya mirip Vitest atau Jest, tanpa perlu install library tambahan. Buat file greet.test.ts untuk menguji fungsi sapa tadi.

typescript
// greet.test.ts
import { test, expect } from "bun:test";
import { sapa } from "./hello";

test("sapa mengembalikan sapaan", () => {
  expect(sapa("Budi")).toBe("Halo, Budi!");
});

Jalankan semua test dengan satu perintah. Bun otomatis mencari file yang berakhiran .test.ts atau .test.js di folder project.

bash
bun test

Membangun REST API dengan Bun.serve

Bun.serve adalah HTTP server bawaan Bun. Tidak perlu Express atau framework tambahan. Server ini dibangun di atas network stack Bun sendiri dan cukup andal untuk API produksi skala kecil sampai menengah. Kita bikin endpoint sederhana dulu.

typescript
// server.ts
const server = Bun.serve({
  port: 3000,
  fetch(req) {
    const url = new URL(req.url);

    if (url.pathname === "/") {
      return new Response("Todo API berjalan. Coba GET /todos");
    }

    if (url.pathname === "/todos" && req.method === "GET") {
      return Response.json([
        { id: 1, task: "Belajar Bun", done: false },
      ]);
    }

    return new Response("Not Found", { status: 404 });
  },
});

console.log(`Server berjalan di ${server.url}`);

Response.json() dan Bun.serve() adalah API global yang tersedia tanpa import. Fungsi fetch menerima object request dan wajib mengembalikan object Response.

Simpan data dengan bun:sqlite

Bun menyertakan driver SQLite yang dikompilasi langsung ke binary-nya. Modul bun:sqlite tidak perlu di-install, dan sintaksnya dekat dengan driver SQLite pada umumnya. Kita perluas server tadi supaya datanya tersimpan di database, bukan di array hardcoded.

typescript
// db.ts
import { Database } from "bun:sqlite";

const db = new Database("todo.sqlite");

db.run(`
  CREATE TABLE IF NOT EXISTS todo (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    task TEXT NOT NULL,
    done INTEGER NOT NULL DEFAULT 0
  )
`);

export function semuaTodo() {
  return db.query("SELECT id, task, done FROM todo ORDER BY id DESC").all();
}

export function tambahTodo(task: string) {
  db.run("INSERT INTO todo (task) VALUES (?)", [task]);
  return db
    .query("SELECT id, task, done FROM todo WHERE id = last_insert_rowid()")
    .get();
}
typescript
// server.ts
import { semuaTodo, tambahTodo } from "./db";

const server = Bun.serve({
  port: 3000,
  async fetch(req) {
    const url = new URL(req.url);

    if (url.pathname === "/todos" && req.method === "GET") {
      return Response.json(semuaTodo());
    }

    if (url.pathname === "/todos" && req.method === "POST") {
      const body = await req.json();
      const task = body.task?.trim();

      if (!task) {
        return Response.json({ error: "task wajib diisi" }, { status: 400 });
      }

      return Response.json(tambahTodo(task), { status: 201 });
    }

    return new Response("Not Found", { status: 404 });
  },
});

console.log(`Server berjalan di ${server.url}`);

Perhatikan async fetch di atas. Bun.serve mendukung handler async, jadi kamu bisa menunggu req.json() untuk membaca body JSON dari request POST. Parameter ? pada query SQL adalah placeholder yang di-escape otomatis, jadi kamu tidak perlu takut SQL injection saat memakai input dari user.

Menjalankan server dan mencoba endpoint

Jalankan server, lalu buka terminal kedua untuk mencoba endpoint-nya dengan curl.

bash
bun server.ts
bash
# Ambil semua todo
curl http://localhost:3000/todos

# Tambah todo baru
curl -X POST http://localhost:3000/todos -H "Content-Type: application/json" -d '{"task": "Tulis artikel Bun"}'

Dari nol sampai API dengan database hanya butuh dua file dan nol dependency eksternal. Kalau kamu masih menulis JavaScript tanpa tipe, baca dulu pengantar TypeScript supaya kode .ts di atas tidak terasa asing. Langkah berikutnya: tambahkan endpoint DELETE /todos/:id dan PUT /todos/:id, lalu jalankan bun test untuk menguncinya dengan test — semua API yang kamu butuhkan sudah ada di artikel ini.

Tanya Jawab Singkat

Apakah Bun sudah stabil untuk produksi?

Bun 1.x sudah rilis stabil dan dipakai di production oleh beberapa tim. Untuk API skala kecil sampai menengah, Bun.serve dan bun:sqlite cukup andal. Kalau project kamu bergantung pada banyak package native Node, cek dulu kompatibilitasnya — sebagian besar package npm jalan normal, tapi modul yang memakai binding native kadang perlu penyesuaian.

Apa bedanya Bun dengan Node.js dan Deno?

Node.js adalah runtime JavaScript yang paling tua dan paling banyak dipakai. Bun dan Deno sama-sama runtime modern dengan fitur built-in seperti TypeScript dan test runner. Bun menonjol di kecepatan install dan package manager-nya, plus server dan SQLite yang menyatu dalam satu binary. Deno lebih fokus pada keamanan lewat izin akses eksplisit per program.