Jump to: What it does · Why it matters · Is it useful? · How it works · Choose an integration style · Quick start · Troubleshooting · Advanced integration
What it does
ic-memory is a safety system for an Internet Computer application's persistent
data.
When an application is upgraded, its code changes but its stored data remains. Each database, log, queue, or settings store must reconnect to the same storage location it used before. If two stores are accidentally swapped, the new code can interpret one kind of data as another.
ic-memory remembers which storage location belongs to each named store. Before
the application opens any of those stores, it checks the new layout against the
saved ownership records. A conflicting upgrade stops with an error instead of
opening the wrong data.
ic-memoryprotects the connection between a store and its storage location. It is not a backup system, a database schema migrator, or a data validator.
Why this matters
Imagine that version 1 of an application stores users and orders separately:
Users -> storage location 100
Orders -> storage location 101
A later version accidentally reverses those locations:
Users -> storage location 101
Orders -> storage location 100
The diagram below shows the same mistake and the point where ic-memory
intervenes:
The program can still compile, and the upgrade can still install. Without an
allocation check, it may then read order records as users and user records as
orders. ic-memory detects the changed ownership before either location is
opened.
This protection matters because a stable-memory location is a durable part of an application's storage layout, even though it can look like an ordinary number in source code.
Is it useful for my application?
ic-memory is most useful for frameworks, generated canisters, multi-store
applications, plugin systems, and canister families that evolve over time.
How it works
The lifecycle has three parts:
- Name each store. The application gives every persistent store a permanent
identity, such as
app.users.v1. - Remember its location. On the first successful installation,
ic-memoryrecords which storage location belongs to each name. - Check before opening. On every installation or upgrade, the new
application version declares the layout it expects.
ic-memorycompares that layout with the remembered one before any application store opens.
If the layouts agree, the application receives permission to open its stores.
If a known name moved, a location changed owner, or another allocation rule is
broken, the check returns an error and ic-memory grants no permission to open
application stores.
This check-and-record operation is called bootstrap. Its important guarantee is validation before open: a diagnostic report or an uncommitted validation result cannot grant access to a store. The runtime publishes permission only after the allocation ledger has been recovered, checked, and durably updated.
The ledger stores one current record per allocated identity and the latest schema metadata. It keeps no per-upgrade or schema-change history. Omitted and retired identities retain their IDs to prevent accidental reuse. A commit counter and two protected commit slots support stale-proof checks and corruption detection.
What happens when a check fails?
Bootstrap returns an error before application stores are opened. ic-memory
does not silently repair, move, discard, or reinterpret a conflicting
allocation. A failed attempt publishes no permission to open stores.
Treat the error as an upgrade-safety signal: keep the existing stable memory, inspect the requested keys, host namespace grants, exclusions, policy and diagnostics, then correct the new application version. Do not erase the allocation ledger or replace it with an empty one to make the error disappear. See the symptom-based troubleshooting guide for safe next steps.
What it protects
Retiring a store does not make its old location reusable. That tombstone is intentional: reusing the location could make a rollback open unrelated data.
Terminology
- A stable key is a permanent store name, such as
app.orders.v1. - A memory ID is the physical
MemoryManagerlocation behind that key. - An authority names the linked component requesting a key.
- A namespace grant admits that authority's keys under a host-selected prefix.
- The allocation pool contains eligible application IDs shared by all owners.
- Bootstrap recovers, admits, resolves, validates and commits before opening.
- The allocation ledger retains key-to-ID bindings and retirement tombstones.
The application owns one pool and one bootstrap per backing memory. Libraries contribute key requests, verify that the host included them, and open their committed keys. Owner labels are current host policy; they are not persisted ownership history, caller authentication or a sandbox for linked code.
Quick start for developers
Add the crate:
[]
= "0.35.1"
ic-memory re-exports its exact ic-stable-structures dependency through
ic_memory::ic_stable_structures. Import collections, backing memories, and
traits through that namespace so their types match the runtime:
use ;
type CounterStore = ;
A separate ic-stable-structures dependency is unnecessary for those imports.
Declare keys; let the host allocate
Components name their owner and permanent keys without choosing IDs:
const MEMORY_AUTHORITY: &str = "example_app";
ic_memory_declaration!;
Call this host bootstrap from initialization and post-upgrade before deferred stable collections open. Hosts needing admission or custom bucket geometry use the policy or configuration bootstrap helpers with the same explicit pool.
Known keys retain their committed IDs. New requests are sorted by key and take the lowest unclaimed ID in the common pool. Current, omitted, reserved and retired records occupy their IDs permanently. Namespace grants do not divide space between components. Exhaustion rejects the entire attempt.
See examples/key_only.rs and
examples/composed_host.rs.
Applications composed from several libraries
Every linked crate contributes requests to one immutable registry. The host
admits disjoint namespaces for their named owners and supplies explicit physical
exclusions for unmanaged MemoryManager clients. All components draw from the
same remaining pool. The application bootstraps the combined layout once.
Libraries adopting an already bootstrapped host can verify that all of their requirements were included without rerunning bootstrap or replacing the host's policy:
Duplicate keys, overlapping namespace grants, foreign owner claims and excluded historical IDs fail before application stores open. Populated IDs without a ledger record must be explicitly excluded by the host; bootstrap refuses to infer custody from stored bytes.
The default runtime reserves IDs 0..=9 and keys under ic_memory.* for its
own governance records. ID 0 contains the allocation ledger. Application
code may use IDs through 254; ID 255 is the upstream unallocated sentinel
and can never be declared.
Stable keys
A stable key names the durable identity of a store, not its current numeric location:
namespace.component.store_or_role.vN
use StableKey;
parse.expect;
parse.expect;
parse.expect;
Changing a key creates a new allocation identity. If the durable store is still the same store, keep its key and change its optional diagnostic schema metadata instead.
Frequently asked questions
No. It validates allocation identity. Schema and data migrations remain the application's responsibility.
No. Keep a separate backup and disaster-recovery plan. ic-memory fails closed
when its allocation metadata cannot be recovered safely.
Bootstrap returns an error and publishes no open capability. Fix the proposed layout or policy; do not erase the ledger to bypass the conflict.
No. Retirement is a permanent tombstone so a future version or rollback cannot mistake unrelated data for the retired store.
No. One owner bootstraps each concrete runtime. Libraries verify their requirements against the host's committed layout and open only their keys.
Each library declares permanent keys and its owner label. The host admits the namespace and owns physical exclusions; Memory assigns IDs and retains them.
Yes, provided its key is new, the host admits its namespace and owner, the common pool has space, and the complete layout passes admission and validation.
Operations and advanced integration
- Operations and diagnostics explains memory attribution, bucket configuration, and runtime reports.
- Troubleshooting maps common symptoms to safe recovery steps.
- Advanced ic-memory covers explicit runtimes, custom policies, recovery, and manual bootstrap.
- Safety invariants records the guarantees future changes must preserve.
- Documentation index separates current guidance from historical engineering evidence.
- Release guide is for maintainers preparing and publishing a release.
ic-memory is pre-1.0 infrastructure extracted from Canic. Current releases use
the current API and durable format only; earlier pre-1.0 wire formats are not a
compatibility target.