skills/migrating-motoko/SKILL.md
Inline actor migration for Motoko canisters using `(with migration = ...)` syntax. Use when upgrading canister state, renaming fields, changing field types, or restructuring actor state without the --enhanced-migration flag. For multi-step migration chains, use migrating-motoko-enhanced instead.
npx skillsauth add dfinity/icskills migrating-motokoInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Migrate actor state across canister upgrades using a migration expression attached to the actor. Each upgrade has at most one migration function.
For multi-migration with a migrations/ directory, load migrating-motoko-enhanced instead.
The runtime allows the upgrade if the new program is compatible with the old:
var ↔ let)Nat → Int)Bool → variant, Int → Float)Parenthetical expression immediately before the actor:
import Migration "migration";
(with migration = Migration.run)
actor {
var newState : Float = 0.0;
};
Or inline:
import Int "mo:core/Int";
(with migration = func(old : { var state : Int }) : { var newState : Float } {
{ var newState = old.state.toFloat() }
})
actor {
var newState : Float = 0.0;
};
Or using the shorthand when the imported module exports a migration field:
import { migration } "migration";
(with migration)
actor { ... };
func (old : { ... }) : { ... } — local, non-generic, both records must use persistable types (no functions or mutable arrays)| Field appears in | Effect | | ---------------- | ------ | | Input and output | Field is transformed | | Output only | New field produced by migration | | Input only | Field consumed (compiler warns about possible data loss) | | Neither | Carried through or initialized by declaration |
Keep migrations in a separate module. Define old types inline — do not import them from old code paths:
// migration.mo
import Types "types";
import Map "mo:core/Map";
module {
type OldTask = { id : Nat; title : Text; completed : Bool };
type OldActor = {
var tasks : Map.Map<Nat, OldTask>;
var nextId : Nat;
};
type NewActor = {
var tasks : Map.Map<Nat, Types.Task>;
var nextId : Nat;
};
public func run(old : OldActor) : NewActor {
let tasks = old.tasks.map<Nat, OldTask, Types.Task>(
func(_, task) {
{
id = task.id;
title = task.title;
due = 0;
var status = if (task.completed) #completed else #pending;
}
}
);
{ var tasks; var nextId = old.nextId };
};
};
// main.mo
import Map "mo:core/Map";
import Types "types";
import Migration "migration";
(with migration = Migration.run)
actor {
var tasks = Map.empty<Nat, Types.Task>();
var nextId : Nat = 0;
};
Fields must have initializers — the migration function runs only on upgrade. On fresh install the initializers are used.
old.users.map<Nat, OldUser, NewUser>(
func(_, u) { { u with zipCode = "" } }
)
{ task with var assignee = null : ?Principal }
var status = if (task.completed) #completed else #pending;
Consume old name, produce new name:
func(old : { var state : Int }) : { var value : Int } {
{ var value = old.state }
}
Consume it in the input, omit from output. Compiler warns — ensure the loss is intentional.
migration.mofunc (old : RecordIn) : RecordOut with persistable types(with migration = Migration.run) before the actorpreupgrade/postupgrade for data migrationmops check --fix and mops buildmotoko for general Motoko language reference and mo:core APIsmigrating-motoko-enhanced for multi-migration with --enhanced-migrationmops-cli for mops check, mops build, and toolchain setuptools
Deploys an already-built Internet Computer project to a user's own cloud engine (an OpenCloud / control-panel engine, administered from a web console). Covers verifying the icp CLI, linking the user's console identity to the CLI with `icp identity link web`, defaulting the console origin to https://opencloud.org (overridable when the user signs in to a different console), obtaining the engine's subnet id (asking the user when it is unknown), running `icp deploy` against that subnet, and tagging the canisters with `__META_*` environment variables so the engine console shows a named app with labelled backend/frontend canisters. Use when a developer wants to ship an app to their cloud engine, mentions a cloud engine, OpenCloud, an engine subnet id, linking the icp CLI to an engine console, or giving a deployed app a name in the console. Do NOT use for a general mainnet deploy with no specific engine or subnet (use the icp-cli skill) or for writing canister code.
tools
Guides use of the icp command-line tool for building and deploying Internet Computer applications. Covers project configuration (icp.yaml), recipes, environments, canister lifecycle, and identity management. Use when building, deploying, or managing any IC project. Use when the user mentions icp, dfx, canister deployment, local network, or project setup. Do NOT use for canister-level programming patterns like access control, inter-canister calls, or stable memory — use domain-specific skills instead.
development
Deploy frontend assets to the IC. Covers certified assets, SPA routing with .ic-assets.json5, content encoding, and programmatic uploads. Use when hosting a frontend, deploying static files, or setting up SPA routing on IC. Do NOT use for canister-level code patterns or custom domain setup — use custom-domains instead.
development
One-time installer that makes a Claude Code project keep its Internet Computer skills up to date automatically. Sets up a SessionStart hook plus a sync script so .claude/skills/ always mirrors the latest skills published at skills.internetcomputer.org. Use when a user wants to install, bootstrap, or enable "always-latest" Internet Computer / IC / ICP / Motoko skills in a project, or pastes the link to this skill. This is a one-time setup action, not ongoing IC knowledge — after it runs, the installed hook keeps skills current on every session. Do NOT use for IC coding questions themselves — this only configures auto-updating skills.