A from-scratch hybrid OLTP/OLAP (HTAP) database engine — columnar by nature.
▶ Try it live in your browser — no install (runs entirely in WebAssembly)
A from-scratch hybrid OLTP/OLAP (HTAP) database engine in C++17 — with a browser-based Workbench. No external dependencies, ~3k lines, built to be fast and readable. It pairs a row store's point-lookup latency with a columnar engine's scan/aggregate throughput, and every performance claim is benchmarked against SQLite, DuckDB, and MySQL on identical data.
Built in the open as a place to learn how a database actually works — and to make it better together. Contributions welcome → CONTRIBUTING.md.
- Columnar + row hybrid: contiguous native-width columns, per-rowgroup zone maps (granule skipping), dictionary-encoded strings, and a vectorized executor — plus a PK hash index for O(1) point lookups.
- Disk-backed & persistent: memory-mapped columns, a growable write-through mapping (2.4M inserts/s), and a versioned on-disk catalog.
- SQL:
CREATE/DROP TABLE,INSERT,UPDATE,DELETE,SELECTwithWHERE/GROUP BY/aggregates/ORDER BY/LIMIT,INNER/LEFT JOIN(hash join, N-way),CREATE/DROP INDEX(LSM secondary indexes), and a queryableinformation_schema. - Types:
BIGINT/INT/DOUBLE/VARCHARplusBOOLEAN,DATE,TIMESTAMP, exactDECIMAL. - Workbench: a local web client with a syntax-highlighted SQL editor (line numbers, autocomplete, Format, history), an object tree with per-table Browse / Structure / Insert / Drop actions, a Structure/DDL view, an editable result grid (inline edit / add / delete rows → generated SQL, resizable columns, cell peek, sort, filter), query-plan view, resizable panels, CSV/JSON export, benchmark templates, and light/dark. Runs natively or entirely in-browser via WASM. See WORKBENCH.md.
- Honest benchmarks: beats SQLite 13–70× and MySQL 16–63× on analytics, wins/ties single-threaded DuckDB on most queries, and documents where it loses and why.
A dependency-free, browser-based SQL client — syntax-highlighted editor, object tree, editable result grid, query plans, and a Structure/DDL view. Try it live (runs entirely in WebAssembly — the screenshots below are the actual playground):
Docs: Usage guide · Benchmarks · transactional/peak-load analysis · Workbench · ROADMAP (what we want to build next, vs each existing DB).
History: Basalt began as a smaller in-memory engine ("v1"). That prototype has been retired — the disk-backed engine here is the mainstream project. The original is preserved at the
v1-finalgit tag.
Platform: Linux or macOS (uses POSIX mmap + sockets; not Windows — use WSL).
Prerequisites
- A C++17 compiler (
clang++org++) andmake. - SQLite dev headers — only needed for the benchmark binary (
basalt-bench), which links-lsqlite3. The CLI and Workbench don't need it. - (optional) Python 3 +
pip install duckdb pymysqlfor the DuckDB/MySQL comparison scripts.
# macOS: compiler ships with Xcode Command Line Tools; SQLite is in the SDK
xcode-select --install # if not already installed
# Debian/Ubuntu:
sudo apt-get install -y build-essential libsqlite3-devClone
git clone https://github.com/basalt-db/basalt.git
cd basaltmake # builds: basalt (CLI), basalt-server, basalt-bench
# just the CLI + Workbench (no SQLite needed): make basalt basalt-server
./basalt mydb # persistent SQL REPL on directory ./mydb
./basalt-server demo_root 8090 # Workbench → open http://127.0.0.1:8090The Workbench starts empty on a fresh clone — click + New DB (or run
CREATE DATABASE …) to make one, then CREATE TABLE …. Point basalt-server at
any directory of Basalt databases. To explore real data, load the IMDb datasets
with basalt-import (see docs/USAGE.md).
CREATE TABLE users (id BIGINT PRIMARY KEY, name VARCHAR, tier INT);
INSERT INTO users VALUES (1,'alice',1),(2,'bob',2);
CREATE INDEX u_tier ON users(tier);
SELECT tier, COUNT(*) FROM users GROUP BY tier;No compiler needed — the engine compiles to WASM and the Workbench runs entirely
in your browser: https://basalt-db.github.io/basalt/. Rebuild it
locally with ./build_wasm.sh (uses the emscripten Docker image) then
serve web/.
The importer loads the public IMDb datasets (~12.6M rows) so you can explore joins, indexes, and the query planner on something real — see docs/USAGE.md.
Official clients let you talk to Basalt from your own code — embedded (no server) or over HTTP. See clients/ for the overview and HTTP API.
JavaScript / TypeScript — basaltdb
(npm) · repo basalt-db/basalt-js —
runs the engine embedded in-process via WebAssembly (Node & browser, like
sql.js) or against a server:
import { Basalt } from 'basaltdb'; // npm install basaltdb
const db = await Basalt.create(); // in-memory, no server
db.exec("CREATE TABLE t (id BIGINT PRIMARY KEY, name VARCHAR)");
db.table('t').insert({ id: 1, name: 'alice' });
db.query('SELECT * FROM t'); // [{ id: 1, name: 'alice' }]Python — basalt-client (PyPI) ·
repo basalt-db/basalt-python —
dependency-free DB-API 2.0-style client over HTTP:
import basalt # pip install basalt-client
con = basalt.connect("http://127.0.0.1:8090", database="mydb")
con.query("SELECT tier, COUNT(*) FROM users GROUP BY tier")Any language — the server exposes a tiny HTTP/JSON API
(POST /api/query, GET /api/schema, …). ORM dialects (Prisma/SQLAlchemy/…)
are on the roadmap, gated on transactions + a Postgres wire
protocol — see clients/README.md for the honest status.
5M-row analytical workload, single-threaded, Apple M1 Pro (full methodology in the benchmark docs — the numbers include honest caveats about in-process vs client-server and durability):
| Query | Basalt | SQLite | MySQL 8.0 | DuckDB (1 core) |
|---|---|---|---|---|
COUNT(*) |
0.0008 ms | 3.8 ms | 66 ms | 0.46 ms |
filtered SUM |
12.8 ms | 173 ms | 506 ms | 4.7 ms |
GROUP BY rollup |
25 ms | 1789 ms | 978 ms | 27 ms |
indexed WHERE id = ? |
0.0034 ms | 0.011 ms | 0.5 ms | 0.17 ms |
See BENCHMARKS.md and BENCHMARKS.md.
SQL ─▶ tokenizer + recursive-descent parser ─▶ AST
│
▼
vectorized executor storage engine (per table)
• zone-map rowgroup skip • columns = mmap'd native-width buffers
• columnar mask filter • zone maps (min/max per 64Ki-row group)
• fused filter+aggregate • string dictionary (→ int32 id)
• hash / direct-map GROUP BY • PK hash index (O(1) point lookup)
• hash JOIN (N-way) • LSM secondary indexes (sorted run + delta)
The single-table path is vectorized and column-at-a-time; joins use hash joins. Reads are lock-shared (concurrent); writes are single-writer. See ROADMAP.md for what's next (vectorized joins, MVCC, compression…).
This is a community project — issues, discussions, and PRs are all welcome, whether it's a bug fix, a new operator, a benchmark, docs, or one of the roadmap items. Start with CONTRIBUTING.md and our Code of Conduct.
- 🌱 New here? Pick a curated starter task from
GOOD_FIRST_ISSUES.md (each has file pointers +
acceptance criteria), or browse the
good first issuelabel. - 💬 Questions / where to ask: SUPPORT.md.
- 🔒 Found a security or memory-safety bug? Report it privately — SECURITY.md.
MIT — do anything, no warranty.


