Live prices are currently unavailable — the exchange feed could not be reached and no recent cached reading is held.

Research · ICP

Canister upgrades and stable memory

A canister's code can be replaced without losing its data, but only if the data is in the right place. Stable memory is the part of a canister's state that survives an upgrade, and the pre-upgrade and post-upgrade hooks are where a canister moves its state across. Getting this wrong is the most common way to lose data on the network.

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.