Skip to content
All projects
SystemsMar 2026Live

QueryForge: A SQL Database Engine Built From Scratch

A SQL Database Engine Built From Scratch

A SQL database you can watch work: a storage engine, B+tree index, write-ahead log, hand-written parser and rule-based planner, each lighting up as your query runs. There is no Postgres underneath. I wrote every layer.

query-forge-charan.vercel.app
QueryForge, the live site
Year
Mar 2026
Timeline
8 weeks
Type
Systems
Status
Live

3 vs 18

Row visits with the index versus without. Flip one toggle and the cost of a missing index shows up on screen.

01

Overview

Most "database demos" are a thin UI over Postgres. In QueryForge the database is the project. Rows live in 4 KB pages, the index is a B+tree where every node is a page, and durability comes from a write-ahead log, built in layers that can each be tested alone. The main feature is that you can see it happen: type SQL and the tokenizer, parser, planner, B+tree and pages animate in order, replayed from the engine's own event log.

02

The hard parts

  1. 01

    Keeping the B+tree balanced: splits have to propagate correctly all the way up to a growing root, or lookups start returning wrong results with no error.

  2. 02

    Durability with no database to lean on: surviving a "pull the plug" meant getting write-ahead logging and replay right.

  3. 03

    Keeping the on-screen animation accurate: it may only show events the engine emitted, never an approximation.

  4. 04

    A bug that took two evenings: stale bytes from a shrunk B+tree node leaked into the next decode, so a leaf "remembered" keys it no longer had.

03

The approach

The engine is pure TypeScript with zero DOM dependencies, so the same code runs in the Vitest suite and in the browser tab. A tracer threads through the pager, B+tree and executor, and the playground is a replay of that event log, so the visualization cannot drift from what the engine did. fast-check property tests cover the parts where correctness is subtle (10,000 random inserts, every lookup correct, every leaf at the same depth) and shrank the split bug to a four-key counterexample in seconds. The fix was one line: zero the node body before re-serializing.

04

Outcome

QueryForge runs entirely client-side. You type a query, watch the plan light up, then flip "force full scan" and see the difference in the row-visit counter. Pull the plug to wipe memory, hit Recover, and the WAL rebuilds every page on screen. Building it is how I came to understand what a database does underneath a query.

05

What I'd do differently

The WAL is logical and replays from the start of history with no checkpoints. That is fine for a teaching engine and painful at scale, so checkpointing is first on the list. I left out DELETE/UPDATE, transactions and JOINs on purpose. The Volcano iterator model already fits a nested-loop-then-hash join, so joins are the next step and would not need a rewrite.

06

Stack

engine
TypeScript (strict)B+treeslotted pagesWAL
frontend
Next.jsReactTailwindCodeMirror 6
testing
Vitestfast-check (property-based)

Like what you see?

Let's build the next one.

Hiring, or have a problem that needs this kind of engineering? I read every message myself.