Research · ICP
Canister upgrades and stable memory
Last reviewed 2026-09-21Source: ICP Developer Docs — Canister upgrades, stable memory and the management canisterThe upgrade mechanism and the stable-memory model are described as documented; the Motoko and Rust differences are stated as the documentation presents them.
What an upgrade replaces
A canister is a WebAssembly module plus a memory. Upgrading a canister replaces the module — the code — while keeping the canister ID, the controllers and the cycles balance. The documentation describes the upgrade as installing a new module over the old one, and the question that decides whether data survives is where that data lived.
The documentation distinguishes two kinds of memory. The WebAssembly heap is the memory the module uses at runtime, and it is discarded when the module is replaced. Stable memory is a separate memory that belongs to the canister rather than to the module, and it survives the replacement. A canister that keeps its state only in the heap loses it on upgrade; a canister that keeps it in stable memory keeps it.
The documentation also describes the upgrade hooks. A canister can export a pre-upgrade function, which runs before the module is replaced, and a post-upgrade function, which runs after. The pre-upgrade hook is where a canister serialises its heap state into stable memory, and the post-upgrade hook is where it reads that state back. The hooks are the bridge between the two memories.
Motoko's orthogonal persistence
Motoko takes a different approach. The documentation describes orthogonal persistence as the property that a Motoko actor's variables persist across upgrades automatically, without the developer writing serialisation code. A Motoko canister declares its state as ordinary variables, and the runtime handles the transition across an upgrade.
The documentation is careful about the limits. Orthogonal persistence applies to the actor's state, and it works because the Motoko runtime manages the mapping between the language's values and the canister's memory. A developer who wants explicit control can still use stable variables and the system functions for pre-upgrade and post-upgrade, and the documentation describes the interaction between the two mechanisms.
The practical consequence is that a Motoko canister is harder to break by forgetting a hook, and a Rust canister is easier to break that way. That is not a claim that one language is better; it is a statement about where the responsibility sits. In Motoko the runtime carries it by default; in Rust the developer carries it explicitly.
Rust and explicit stable structures
In Rust the developer manages persistence. The documentation describes the stable structures the CDK provides — stable vectors, stable logs, stable cell, stable B-tree maps and sets — which store their data in stable memory directly rather than in the heap. A canister built on stable structures keeps its data across an upgrade without a serialisation step, because the data was never in the heap to begin with.
The alternative is to keep state in the heap and move it in the hooks. The documentation describes the pre-upgrade hook as the place to write the heap state into stable memory and the post-upgrade hook as the place to read it back. This works, but it has a cost: the serialisation happens inside the upgrade, and a large state can exceed the instruction limit for a single message. The documentation notes that the upgrade can be split across multiple messages when that happens.
The documentation also describes the memory limits. A canister's stable memory is much larger than its heap, and the heap itself is bounded. A canister that needs to hold a lot of data must use stable memory, which in Rust means stable structures and in Motoko means the runtime's persistence. The Motoko versus Rust page compares the two approaches in more detail.
The failure modes
The documentation describes what happens when an upgrade fails. If the new module cannot be installed, or if the pre-upgrade hook traps, the upgrade does not complete and the canister continues running the old code. That is a safety property: a broken upgrade does not leave the canister in a half-updated state. The cost is that the canister is still running the old code, which may be the thing the upgrade was meant to fix.
The more dangerous failure is a successful upgrade that loses data. If the pre-upgrade hook does not write everything the post-upgrade hook expects, the canister comes up with a partial state. The documentation's guidance is to test upgrades against a copy of production state, which is the only way to be sure the hooks agree.
The documentation also notes that a canister's controllers can upgrade it, and that the management canister exposes the upgrade operation. That means the authority to change a canister's code is the authority to change its behaviour entirely, which is why the SNS handover is a meaningful act rather than a symbolic one.
Sources and references
The upgrade mechanism, the two memories and the language-specific approaches are described from the Internet Computer's own documentation.
- Canister code, memory and upgrades. ICP Developer Docs, Canisters and code: describes the module, the heap, stable memory and the upgrade operation.
- Stable memory and the upgrade hooks. ICP Developer Docs, Stable memory: covers the pre-upgrade and post-upgrade system functions, the memory limits and the multi-message upgrade.
- Motoko orthogonal persistence. ICP Developer Docs, Actors and orthogonal persistence: explains how Motoko persists actor state across upgrades and how stable variables interact with it.
Related reading
- Research HubEvery dataset on the site, with methodology and provenance.
- Altcoin ResearchAltcoins measured against Bitcoin: design intent, consensus, execution, scaling and market structure.
- The ETH-BTC Correlation RecordHow the correlation is measured, how it behaves across windows, and where it breaks down.
- The ETH/BTC RatioWhat the ratio measures, how to read its trend, and why it is not a forecast.
- ETH During Bitcoin Bull PhasesAssociation within a common market factor, and what co-movement cannot establish.
- ETH During Bitcoin Bear PhasesDrawdown depth and duration compared over identical windows, and the limits of the comparison.