Nothing is written over
Every change keeps the version before it. Last Tuesday is a question you ask, not a backup you restore and pray about.
Eelgrass goes as wide as it goes deep. Ten thousand customers with a megabyte each, or one with a terabyte, on the same engine, keeping every version of everything. It grows with your company instead of being replaced by it.
Every other database makes you pick. Postgres goes deep and turns ugly the day every customer needs their own. The edge databases go wide and stop each one at ten gigabytes. The warehouses go deep on reading and give up on writing.
We are building the one that refuses to choose. A database here is a node in a tree: your account holds databases, a database holds a tenant for every customer you have, and any node can be the big one.
Going wide costs almost nothing, because a database nobody is using costs about what one row costs. Going deep does not change the shape, because the machine is a cache and the data lives in object storage.
So there is no migration waiting for you in year three. The database you launch on is the one you are still running when you have a thousand customers and a decade of history.
A customer with 28 gigabytes of data, on the smallest instance Amazon sells.
| Memory the machine serving it needs | 35 MB |
| Copy that whole customer | 100 ms |
| Throw the copy away again | 49 ms |
| Read twenty thousand rows | 1.1 seconds |
| Load the 28 gigabytes in | 41 MB a second |
The machine holds 35 megabytes of a 28 gigabyte database, because the data lives in object storage and the machine is only a cache. That is also why copying a customer does not get slower as they grow: the same copy took longer at 1.35 gigabytes than it does at 28.
The middle column is what you write. The right-hand column is what your team is doing instead, right now.
| What you need to do | Here | Everywhere else |
|---|---|---|
| Undo six hours of bad writes, and nothing else | orders |> filter batch == b |> revert to now() - 6h | Restore last night's backup and lose every order taken since. Or build an undo by hand and hope it was right. |
| Ask what a record said at any moment | orders |> asof "2026-09-01T09:00" |> filter id == oid | A point-in-time restore onto a second machine, or an audit-table project, per table, forever. |
| Copy a customer to test against | fork tenant "acme" as "acme-staging" | Export, scrub, restore. Slow enough that people stop bothering and test against made-up data. |
| Delete one customer, completely | delete tenant "acme" | A delete per table, in the right order, and a promise that nobody missed one. |
| Change two customers with a checked undo | flow { step ... compensate ... } | A saga framework, or a distributed transaction nobody trusts. |
| Hand a customer their data and leave | eelgrass export ./crm acme acme.eelpkg | A ticket, a script, and a week. |
| What you need to do | Here | Everywhere else |
|---|---|---|
| Get every change, with the fields that changed | GET /t/acme/tail?after=412 | Logical replication, a change-capture service, a topic, and a consumer that puts the row back together. |
| Report across customers without a warehouse | rollup Daily { across tenants (name == "acme/*") ... } | A copy of the database, a warehouse, a pipeline between them, and two teams to change one number. |
The second table arrives with invoices, so somebody notices it. The first arrives with salaries, and it lands on the people you can least afford to have doing it.
You are not buying a faster database. You are deleting the right-hand column.
See every line of the middle column run properly
We are building with a small number of companies who have these problems and want a say in what gets built.