Install
$ agentstack add skill-dfinity-icskills-migrating-motoko ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Inline Actor Migration
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.
When to Use
Implicit migration (no code needed)
The runtime allows the upgrade if the new program is compatible with the old:
- Adding actor fields
- Removing actor fields
- Changing mutability (
var↔let) - Adding variant constructors
- Widening types (
Nat→Int)
Explicit migration required
- Renaming fields
- Changing a field's type (e.g.
Bool→ variant,Int→Float) - Restructuring state (splitting/merging fields)
- Transforming collection values
Syntax
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 { ... };
Migration Function Rules
- Type:
func (old : { ... }) : { ... }— local, non-generic, both records must use persistable types (no functions or mutable arrays) - Domain: old actor fields (names and types from the previous version)
- Codomain: new actor fields (must exist in the new actor with compatible types)
- Runs only on upgrade — on fresh install, initializers run normally
- If the migration traps, the upgrade is aborted and the canister stays on the old version
Field semantics
| 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 |
Migration Module Pattern
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;
var nextId : Nat;
};
type NewActor = {
var tasks : Map.Map;
var nextId : Nat;
};
public func run(old : OldActor) : NewActor {
let tasks = old.tasks.map(
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();
var nextId : Nat = 0;
};
Fields must have initializers — the migration function runs only on upgrade. On fresh install the initializers are used.
Common Patterns
Add field with default
old.users.map(
func(_, u) { { u with zipCode = "" } }
)
Add optional field
{ task with var assignee = null : ?Principal }
Bool to variant
var status = if (task.completed) #completed else #pending;
Rename a field
Consume old name, produce new name:
func(old : { var state : Int }) : { var value : Int } {
{ var value = old.state }
}
Drop a field
Consume it in the input, omit from output. Compiler warns — ensure the loss is intentional.
Checklist
- [ ] Decide: implicit (compatible change) or explicit (migration function)
- [ ] If explicit: define old types inline in
migration.mo - [ ] Migration type:
func (old : RecordIn) : RecordOutwith persistable types - [ ] Attach with
(with migration = Migration.run)before the actor - [ ] Do not use
preupgrade/postupgradefor data migration - [ ] Verify with
mops check --fixandmops build
Additional References
- Load
motokofor general Motoko language reference and mo:core APIs - Load
migrating-motoko-enhancedfor multi-migration with--enhanced-migration - Load
mops-cliformops check,mops build, and toolchain setup
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: dfinity
- Source: dfinity/icskills
- License: Apache-2.0
- Homepage: https://skills.internetcomputer.org
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.