sqlitend · stress-test report · 2026-09-06

The One-Gigabyte Test

Twenty isolated databases, 200,000 rows, 2.24 million read/update operations, and a full destroy cycle — zero failures on a virtual machine with one CPU core and one gigabyte of RAM.

Machine1 vCPU · 1 GB RAM
PlatformLinux aarch64 (Debian 13)
sqlitend0.1.0 · bind 0.0.0.0
sqld0.24.32 (pinned, SHA-256)
Driver@libsql/client over Hrana WS
200,000
Rows inserted
10,000 per database · every count verified exact
2.24M
Read / update ops
8 rounds × 20 databases, SELECT + UPDATE + metrics
20
Databases
2 workspaces · isolated sqld process + signing key each
0
Failures
creates, inserts, reads, updates, deletes — all clean
CCreate & loadtwo parallel workers · 4-column multi-row INSERT

Two writers each created a workspace and ten databases, minted a per-database token, built a table, and inserted 10,000 rows in batches of 250 four-column rows. Every database responded with an exact COUNT(*) of 10,000 and a LIKE-scan check before being counted.

workspace stress-01 · 10 databases · 100,000 rows · 13.8s

db-01-0110,267/s
974 ms10k ✓
db-01-029,533/s
1049 ms10k ✓
db-01-039,775/s
1023 ms10k ✓
db-01-0410,417/s
960 ms10k ✓
db-01-059,588/s
1043 ms10k ✓
db-01-069,960/s
1004 ms10k ✓
db-01-079,302/s
1075 ms10k ✓
db-01-0811,086/s
902 ms10k ✓
db-01-099,569/s
1045 ms10k ✓
db-01-109,747/s
1026 ms10k ✓

workspace stress-02 · 10 databases · 100,000 rows · 13.9s

db-02-019,990/s
1001 ms10k ✓
db-02-029,234/s
1083 ms10k ✓
db-02-0310,050/s
995 ms10k ✓
db-02-0410,173/s
983 ms10k ✓
db-02-0510,040/s
996 ms10k ✓
db-02-0610,070/s
993 ms10k ✓
db-02-079,524/s
1050 ms10k ✓
db-02-0810,582/s
945 ms10k ✓
db-02-099,960/s
1004 ms10k ✓
db-02-109,699/s
1031 ms10k ✓
R/URead & update hammer8 rounds · sequential per DB, from a remote client over Tailscale

A third worker waited for all 200,000 rows, then ran eight rounds against every database: SELECT COUNT(*), UPDATE of every fifth row, a SELECT by updated value, a top-5 read, and the live /metrics endpoint. Each round touches all 20 databases — 280,100 operations per round.

RoundOperationsAvg latencyp95 latencyFailures
1280,100119.3 ms 175 ms0
2280,100114.8 ms 143 ms0
3280,100112.7 ms 135 ms0
4280,100112.3 ms 126 ms0
5280,100129.4 ms 202 ms0
6280,100118.7 ms 144 ms0
7280,100114.0 ms 129 ms0
8280,100118.6 ms 144 ms0
Total2,240,800mean 117.5 msmean p95 150 ms0
DDestroy & cleanupthe delete path under load & after

Every database was deleted through the API, then the workspaces were removed. The control plane killed each sqld process, freed its port, removed its data directory and its per-database signing key, and cleaned now-empty parents — a gap found during this test and fixed in the same session.

Delete latency

per database (20 deletes)
20 – 41 ms
workspace removal
204 · ~0.3 s
sqld processes after
23 → 3

Residue check

Per-database keys removed from keys/, data directories gone from disk, API back to the pre-test workspace set. The empty-parent cleanup found in the test is now covered by unit tests (parents removed when empty, preserved when siblings remain). Destroy-phase figures here are from the run log; the headline totals are in the linked evidence file.

HThe machine under ithost sampled every 3 s during the run

Peaks observed on a 1-GB box

Host memory used
386 / 969 MB (peak)
All sqld processes RSS
584 MB (peak)
Concurrent sqld processes
23 (peak)
Concurrent databases
23
Control-plane API latency
max 1.4 ms (sampled)
Load average (1 vCPU)
peak 1.43

Footprint per database

sqld resident set
~26 MB
Disk for 10,000 rows
~6.4 MB
Cost per row on disk
~640 bytes
Samples at idle (CPU)
0.2 – 0.8%
MMethod & honesty

How it ran

Three workers: two writers (10 databases each, batched 250-row multi-value inserts via @libsql/client over Hrana WebSocket) and one reader/verifier. Every insert batch verified with an exact COUNT(*). A 3-second host sampler recorded memory, process count, port latency, and database count throughout. The whole run fitted comfortably — ~580 MB was still free at the hottest instant, with no swap.

Caveats

This is a single-node, single-CPU test on deliberately small hardware — a production box is bigger. Latencies include a Tailscale link, not pure loopback. The control plane has no login in v1: put it behind a firewall or authenticated reverse proxy on a real network. Database tokens are per-database and full-access; data access itself stayed isolated — a token for one database was rejected by every other (verified in this run).