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.
Stable vs shared types
Section titled “Stable vs shared types”While all shared types are stable, the reverse is not true. Some stable types cannot be shared across canisters.
| Type | Stable | Shared |
|---|---|---|
Primitive types (Nat, Text, Bool, etc.) | Yes | Yes |
Immutable arrays ([T]) | Yes* | Yes** |
Mutable arrays ([var T]) | Yes* | No |
| Records with immutable fields | Yes | Yes |
| Records with mutable fields | Yes | No |
Option types (?T) | Yes* | Yes** |
| Variants with stable types | Yes | No (if non-shared types are included) |
| Shared functions | Yes | Yes |
| Actor references | Yes | Yes |
| Regions | Yes | No |
Error type (Error) | No | No |
Non-shared functions and futures (async* T) | No | No |
* provided T is stable.
** provided T is shared.
Common stable types
Section titled “Common stable types”Primitive types
Section titled “Primitive types”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;
};Immutable and mutable collections
Section titled “Immutable and mutable collections”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 with mutable or immutable fields
Section titled “Records with mutable or immutable fields”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 with stable type tags
Section titled “Variants with stable type tags”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
Section titled “Option types”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;};Regions
Section titled “Regions”The Region type, which provides low-level memory management, is stable.
persistent actor { // Regions are stable var storage : Region = Region.new(); }Actor references
Section titled “Actor references”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;};Objects with mutable fields
Section titled “Objects with mutable fields”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; };};