b
LearnBun.org

SQLite with Bun

Most JavaScript runtimes treat SQLite as a third-party concern. You install better-sqlite3 or sqlite3, wait for the native bindings to compile, hope the version matches your Node, and try again on the next machine. Bun skips all of that. SQLite is built in.

Open a database

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

const db = new Database("notes.db");

That's the whole setup. The file is created if it doesn't exist. If you pass ":memory:" instead of a filename, the database lives in RAM and disappears when the process exits — useful for tests.

Create a table and insert a row

db.run(`
  CREATE TABLE IF NOT EXISTS notes (
    id INTEGER PRIMARY KEY,
    body TEXT NOT NULL,
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
  )
`);

db.run("INSERT INTO notes (body) VALUES (?)", ["Hello, Bun."]);

db.run executes a statement and returns nothing useful. ? is a placeholder; the array fills it in. Always use placeholders. String concatenation here is a SQL injection bug waiting to happen.

Read rows back

const rows = db.query("SELECT id, body FROM notes").all();
console.log(rows);
// [{ id: 1, body: "Hello, Bun." }]

db.query builds a prepared statement. .all() returns every row. .get() returns the first row, .values() returns plain arrays instead of objects. Pick whichever shape you need.

What's next

This is the surface. You'll want to know about transactions, prepared statements you reuse, and migrations. We'll cover those in a follow-up.

Feedback