AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Migrating Motoko

skill-dfinity-icskills-migrating-motoko · by dfinity

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.

— No reviews yet
0 installs
35 views
0.0% view→install

Install

$ agentstack add skill-dfinity-icskills-migrating-motoko

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No 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.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-dfinity-icskills-migrating-motoko)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
● 2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

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 →
Are you the author of Migrating Motoko? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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) : RecordOut with persistable types
  • [ ] Attach with (with migration = Migration.run) before the actor
  • [ ] Do not use preupgrade/postupgrade for data migration
  • [ ] Verify with mops check --fix and mops build

Additional References

  • Load motoko for general Motoko language reference and mo:core APIs
  • Load migrating-motoko-enhanced for multi-migration with --enhanced-migration
  • Load mops-cli for mops 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.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.