I've been building a small journaling app in Bun and wanted to introduce a database. Drizzle felt like the right fit: it's type-safe, stays close to SQL and has first-class support for Bun's native SQLite driver.
Installation
Drizzle is currently in beta, so both packages need the @beta tag:
bun add drizzle-orm@beta
bun add -d drizzle-kit@beta @types/bundrizzle-kit is the CLI tool that handles schema pushes, migrations and Drizzle Studio.
It goes in devDependencies since it's only needed during development.
Scripts
The package.json scripts need a bun --bun prefix on the drizzle-kit
commands:
"scripts": {
"drizzle:push": "bun --bun drizzle-kit push",
"drizzle:studio": "bun --bun drizzle-kit studio"
}The --bun flag tells Bun to resolve the SQLite driver through its own runtime rather than falling back to a Node.js-compatible shim.
Config
Create drizzle.config.ts at the project root. This tells drizzle-kit where your schema lives, which dialect to use and how to connect:
import { defineConfig } from "drizzle-kit";
export default defineConfig({
out: "./drizzle",
schema: "./src/db/schema.ts",
dialect: "sqlite",
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});Set DATABASE_URL in your .env:
DATABASE_URL=file:./journal.dbClient
Create the database client at src/db/index.ts. The bun-sqlite import is the Bun-native driver, distinct from the generic sqlite adapter:
import { drizzle } from "drizzle-orm/bun-sqlite";
import * as schema from "./schema";
export const db = drizzle(process.env.DATABASE_URL!, { schema });Passing schema here enables relational queries via db.query.
If you're only using the query builder, it's optional.
Schema
Create src/db/schema.ts and define your tables. Here's a simple notes table:
import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";
export const notesTable = sqliteTable("notes", {
id: int().primaryKey({ autoIncrement: true }),
content: text().notNull(),
createdAt: int({ mode: "timestamp_ms" }).notNull(),
updatedAt: int({ mode: "timestamp_ms" }).notNull(),
});int({ mode: "timestamp_ms" }) is worth calling out: it stores timestamps as
integers (milliseconds since epoch) in SQLite and maps them to JS Date objects
in Drizzle. That means you can assign new Date() or Date.now() directly
without a conversion layer.
Pushing the schema
bun drizzle:pushThis applies schema changes directly to the database. For development, it's the
fast path: no migration files, just push and query. For production, you'd want
drizzle-kit generate to produce tracked SQL migration files, then
drizzle-kit migrate to apply them.
Once the schema is pushed, Drizzle Studio gives you a local web UI to browse and edit the database contents:
bun drizzle:studioContinue reading
Mar 2026
·10 min read
Apr 2026
·4 min read