[← Blog]

Declared, Not Registered

A central schema registry is a phone call you have to make before you’re allowed to work. Define a new shape, and first you must publish it — upstream, to a service, and wait for the world to acknowledge the name before your own machine will honor it. We deleted the phone call. An app now declares its schema to its own node, and the name it gets back is exactly the one the central registry would have assigned. Not similar. The same 64 characters.

The app in question is Brain — one of two apps we build LastDB with, both running on LastDB. It wanted a new kind of record: a decision, with a handful of real columns. In the old arrangement, declaring that shape meant registering it with a central schema service and waiting for it to propagate before a fresh node would load it. A local idea, gated on a round-trip to a registrar.

The name is the shape

The trick is that a schema’s canonical name isn’t handed down by a registrar — it is computed from the schema itself. Field names, types, the structure entire: run it through a hash and you get a 64-character fingerprint. Content-addressed, the way a git commit is named by its content and not by who pushed it. Two people who write byte-identical schemas, on opposite ends of the earth, offline, get byte-identical names — because the name was never a decision anyone made. It was a fact about the shape.

So an app can declare its schema locally — hand the shape to its own node — and the registry can register that same schema centrally, and the two arrive at one name without ever consulting each other. Convergence isn’t coordinated. It’s a property of the arithmetic.

AN APP, LOCALLY declares its schema to its node THE REGISTRY registers the same schema CONTENT-ADDRESSED ONE CANONICAL NAME 61b22ab4 … 925d7c
Fig. 1 — two roads, one name: the fingerprint is a fact about the shape, not a registrar's decree

We watched it converge

We declared Brain’s decision schema to a live node with the central service deliberately out of the loop. The node minted a canonical name: 61b22ab4…925d7c. Then we compared it to the fingerprint the central registry computes for the very same shape.

Identical. To the character. The app had named its schema without permission, and named it correctly — because there was only ever one correct name, and the shape already contained it.

The node keeps a small adapter

An app doesn’t want to think in 64-hex fingerprints; it wants to call its record a decision. So the node keeps a tiny per-app table: the app’s own name for a schema on one side, the canonical fingerprint on the other. Declaring a schema writes one row into it — a local mint. The app speaks its own vocabulary; the node quietly translates every reference into the content-address that the rest of the world would recognize.

THE APP calls it “decision” MINT THE NODE — PER-APP ADAPTER THE APP’S NAME ( brain , “decision” ) → 61b22ab4 … 925d7c RESOLUTION: MINT
Fig. 2 — the node's per-app adapter: the app's chosen name, mapped to the canonical fingerprint it minted

This is what “the app owns its schema” actually buys you. Ownership isn’t a label on a permissions screen — it’s the app being able to name its own shapes, locally, and still be globally interoperable, because the naming function is shared arithmetic rather than a shared server. No registrar in the hot path. No propagation delay. Nothing to be down.

The last inch we’re still closing

Honesty, because this is a working system and not a brochure: declaring a schema today establishes its identity — the mapping is written, the name agreed. But to actually query against that shape, the node still has to load it into its live, queryable set, and on current nodes that last step can still lean on the central service to hand over the shape.

So the fingerprint converges with no phone call; the query path doesn’t, quite, yet. We’re closing that gap — teaching the node to materialize a shape straight from a local declaration — so that declaring a schema is, end to end, all it takes. Declared should be enough.

DECLARED identity agreed · mapping written LOADED materialized into the queryable set THE LAST INCH CLOSING — SO DECLARATION ALONE SUFFICES
Fig. 3 — declared is the name; loaded is the use; we're closing the inch between them

Why bother deleting the phone call

Because a central registry in the critical path is a coordination point, and coordination points are where systems wait, stall, and go down. Make the name a function of the shape, and the coordination evaporates: every node can name every schema the same way, alone, offline, instantly — and still agree with every other node in the world. The registrar becomes a convenience, not a gatekeeper. The apps were always the authors of their shapes. Now they get to sign their own work.

Built with Brain and Kanban — open-source apps on LastDB. See also Against Migration, on why the app — not the database — owns the shape of its data.

[← Blog]