Versioning & Updates
Content-addressed apps are immutable — so how does a developer update one? Through an explicit, safe, observable versioned-name registry, not by mutating the app in place.
The model
A name (a subname under chainrender.eth, e.g. swap.chainrender.eth) resolves to a current version, backed
by:
- Append-only history — every version ever pointed-to stays resolvable forever. Immutable lineage.
- A timelock — a queued version doesn't go live until a public delay elapses, so users and wallets can observe and audit it before it activates. No silent swap.
- Opt-in following — a consumer chooses "always latest" (trusts the pointer) or "pinned to a specific version" (ignores the pointer entirely, maximum safety).
How it's exposed
Versioning lives in the on-chain SubnameVersionRegistry — an ownerless contract keyed by your subname. You
interact with it directly (via viem/ethers); the render + resolve side is free view calls. See
Update a Deployed App for the exact calls.
Update your app
queueVersion(myName, newHash) → goes live after your name's timelock
No new ENS write, no hand-rolled update contract, no hidden owner-setter. The trust cost is standardized and visible: a name declares its posture (frozen / timelocked / renounced), and its grade reflects it.
Why this preserves the guarantee
The targets stay immutable — every version is a frozen, content-addressed hash. Only the pointer moves, only on a public delay, and only by the name's own controller (the registry has no admin). A cautious user pins to a hash and ignores the pointer. The name is opt-in convenience over immutable truth.
The clean division
- Cosmetic change (color, spacing) → render-time, zero gas, no version. See Theming.
- Substantive change (features, text, actions) → a new version — public, timelocked, immutable.
Together, presentation + versioning cover the whole "how do I evolve my app safely" question.
Related
- Guides → Update a Deployed App
- Content Addressing — the immutability this builds on.