For AI agents: Documentation index at /llms.txt

Skip to content

Stable types

Stable types include all shared types and represent the kinds of values that can be stored in the stable declarations of a Motoko actor. Storing a value in a stable declaration ensures that it persists across canister upgrades. This enables state preservation without the need for an external file system or database.

The set of stable types defines the kinds of values that can be transferred from an actor to its future upgraded versions. Types that cannot be transferred include those whose values depend on the actor’s current code, such as non-shared functions or, more generally, objects containing function members. These types are not stable because their behavior cannot be preserved independently of the code that defines them.

To give the user more flexibility, the set of stable types is larger than the set of shared types and includes mutable types. This means that programmers can store their application state using a wide range of imperative (stateful) as well as functional (stateless) data structures.

While all shared types are stable, the reverse is not true. Some stable types cannot be shared across canisters.

TypeStableShared
Primitive types (Nat, Text, Bool, etc.)YesYes
Immutable arrays ([T])Yes*Yes**
Mutable arrays ([var T])Yes*No
Records with immutable fieldsYesYes
Records with mutable fieldsYesNo
Option types (?T)Yes*Yes**
Variants with stable typesYesNo (if non-shared types are included)
Shared functionsYesYes
Actor referencesYesYes
RegionsYesNo
Error type (Error)NoNo
Non-shared functions and futures (async* T)NoNo

* provided T is stable. ** provided T is shared.

Most primitive types in Motoko are stable.

persistent actor {
// Numbers, text, booleans and other primitive types are stable
var counter : Nat = 0;
var greeting : Text = "Welcome";
var isActive : Bool = true;
};

Both immutable and mutable collections of stable types are stable.

persistent actor {
// Immutable arrays are stable
var usernames : [Text] = ["Motoko", "Ghost"];
// Mutable arrays are also stable (unlike shared types)
var scores : [var Nat] = [var 100, 85, 92];
};

Records that contain only stable types remain stable, regardless of whether their fields are mutable or immutable.

persistent actor {
// Records with immutable fields are stable
var config = {
appName = "My_Motoko_App";
version = "1.0.0";
};
// Records with mutable fields are also stable
var settings = {
var darkMode = false;
var notifications = true;
var port = 80;
};
};

Variants are stable when their tags contain only stable types.

persistent actor {
// Variants with stable tags are stable
type UserStatus = {
#online;
#offline;
#busy : Text;
};
var motokoStatus : UserStatus = #online;
var ghostStatus : UserStatus = #busy("In a meeting");
};

Option types are stable when they contain stable types.

persistent actor {
// Option types with stable inner types are stable
var optionalDeadline : ?Nat = ?1640995200000;
var optionalMessage : ?Text = null;
};

The Region type, which provides low-level memory management, is stable.

persistent actor {
// Regions are stable
var storage : Region = Region.new();
}

References to actors are stable, allowing stable canister-to-canister interactions.

persistent actor {
// Actor types are stable
type LoggerActor = actor {
log : shared (message : Text) -> async ();
};
var logger : ?LoggerActor = null;
};

Simple objects with mutable fields (but no methods) are stable. Such simple objects are the same as records.

persistent actor {
object user = {
var name = "Motoko";
var loginCount = 0;
};
};