| name | mops-cli |
| description | Manage Motoko projects with the mops CLI — toolchain pinning, dependency management, type-checking, building, and linting. Use when working with mops.toml, mops.lock, running mops commands, adding/removing packages, pinning moc or lintoko versions, checking or building canisters, configuring moc flags, or setting up a new Motoko project. |
Mops CLI
Opinionated guide for Motoko projects. Covers project config, dependency management, type-checking, building, and linting.
Key Principles
- No dfx — always pin
moc in [toolchain]. Use the newest moc version. Pin pocket-ic too if you have replica tests or benchmarks (otherwise mops test --mode replica, mops bench, and mops watch fall back to the deprecated dfx replica and print a warning).
- No
mo:base — it is deprecated. Always use mo:core (import Array "mo:core/Array").
- All config in
mops.toml — canisters, moc flags, toolchain versions, build settings.
- Canister-centric workflow — define all canisters in
[canisters]; never pass file paths to mops check. Exception: library packages (no [canisters]) use file paths directly: mops check src/**/*.mo.
Project Setup
Minimal mops.toml
[toolchain]
moc = "1.7.0"
lintoko = "0.10.0"
pocket-ic = "12.0.0"
[dependencies]
core = "2.5.0"
[moc]
args = ["--default-persistent-actors", "-W=M0223,M0236,M0237"]
[canisters.backend]
main = "src/backend/main.mo"
[canisters.backend.migrations]
chain = "src/backend/migrations"
check-limit = 10
[canisters.backend.check-stable]
path = "deployed/backend.most"
[build]
outputDir = "src/backend/dist"
args = ["--release"]
check-stable runs ICP's upgrade-time stable-variable compatibility check locally, so incompatible changes fail in mops check instead of being rejected when upgrading a live canister. It compares the current code against a .most from the deployed version.
Bootstrap that .most: new project → mops deployed init (empty-actor baseline); already-deployed canister → build from the deployed commit, then mops deployed. After every deploy, run mops deployed to promote the just-built .most (see mops deployed below).
Optional canister fields: candid (path to .did for compatibility checking), initArg (Candid-encoded init args).
Warning Flags
-W=M0223,M0236,M0237 — redundant type instantiation (M0223), suggest contextual dot notation (M0236), suggest redundant explicit arguments (M0237). These are allowed (disabled) by default; -W= enables them as warnings.
Moc Args Layering
Flags are applied in this order (later overrides earlier):
[moc].args — global, all commands (check, build, test, etc.)
[build].args — build only (e.g. --release)
[canisters.<name>.migrations] — auto-injected --enhanced-migration (managed by mops)
[canisters.<name>].args — per-canister
- CLI
-- <flags> — one-off overrides
Core Commands
mops install
mops install
Run after cloning or after manual mops.toml edits. Updates mops.lock. In CI, uses --lock check by default (fails if lockfile is stale).
mops add <package>
mops add core
mops add core@2.5.0
mops add --dev test
Updates mops.toml and mops.lock.
mops check
Primary correctness command — runs moc check, then check-stable (if configured), then lint (if lintoko is in toolchain).
mops check
mops check backend
mops check --fix
mops check --verbose
mops check -- -Werror
Always use canister names, not file paths. Per-canister args from mops.toml are applied automatically.
--fix applies machine-applicable fixes from both moc and lintoko in one pass. Concurrent --fix runs (across processes) serialize automatically via an advisory lock at .mops/fix.lock — safe to invoke from multiple agents on the same project. Read-only files (e.g. frozen migrations) are skipped with a warning, not fixed.
mops build
mops build
mops build backend
mops build --verbose
mops build -- --ai-errors
Produces .wasm, .did, and .most files in [build].outputDir (default .mops/.build).
mops deployed
Post-deploy hook — keeps the on-disk .most baseline used by check-stable in sync with what's actually deployed.
mops deployed init backend
mops deployed backend
mops deployed
Default destination is deployed/<name>.most; override with [deployed].dir in mops.toml or --dir. It reads built .most files from [build].outputDir (default .mops/.build); override with --build-dir. mops deployed errors if the source .most is missing — it never regenerates. Run it from your deploy pipeline immediately after a successful deploy.
mops generate candid
mops generate candid
mops generate candid backend
mops generate candid backend -o <path>
(Re)generates the curated .did from current Motoko source. With [canisters.<name>].candid set, overwrites that file. Without it, writes <name>.did next to main (e.g. main = "src/Backend.mo" → src/backend.did) and sets [canisters.<name>].candid in mops.toml. Run after every interface change; commit .did + mops.toml together. Same moc invocation as mops build, so the result always passes mops build's subtype check.
mops toolchain
mops toolchain use moc 1.7.0
mops toolchain use moc latest
mops toolchain use lintoko 0.10.0
mops toolchain use pocket-ic 12.0.0
mops toolchain update moc
mops toolchain update
mops toolchain bin moc
Agent note: toolchain use <tool> without a version opens an interactive picker — do not use in scripts or agents. Always pass a version or latest. toolchain update only works when the tool already has a [toolchain] entry.
Enhanced migrations
When [canisters.<name>.migrations] is configured, mops check, mops build, and mops check-stable automatically inject --enhanced-migration. Do not add --enhanced-migration to [canisters.<name>].args — mops will error.
Create migration files directly in the chain directory.
After mops check --fix (or mops check <canister>) confirms the chain compiles, run mops build to produce the wasm artifact.
check-limit (optional) caps how many recent chain files mops check and mops lint consider — useful when the chain grows long and re-checking every old migration slows feedback down. mops build is unaffected by check-limit. When the limit kicks in, mops stages the included files into .migrations-<canister>/ next to the chain directory (auto-.gitignored). moc diagnostics may then print paths there — the real file lives in the chain directory with the same name.
Override check-limit for a single run with --no-check-limit (mops check, mops check-stable, mops lint) — e.g. mops check --fix --no-check-limit to autofix older, normally-trimmed migrations. On mops check and mops check-stable, --no-check-limit also suppresses the pending-migration warning.
When check-limit is set, mops check-stable (and the stable check inside mops check) reports if more migrations are pending than the limit allows — as an error if compat failed (replacing the misleading moc message), otherwise a warning.
mops remove <package>
mops remove base
Dependency Management
mops outdated
mops update
mops update core
mops update --major
mops update --patch
mops sync
Other Commands
mops test
Tests live in test/*.test.mo:
mops test
mops test my-test
mops test --mode wasi
mops test --reporter verbose
mops test --watch
Replica tests (actor files or // @testmode replica) use pocket-ic from [toolchain]. With no pin they fall back to the deprecated dfx replica (warning printed) — pin pocket-ic in [toolchain] to silence it. Same applies to mops bench and mops watch.
mops lint
Runs lintoko (also runs automatically as part of mops check when lintoko is in toolchain):
mops lint
mops lint --fix
mops lint <name>
When [canisters.<name>.migrations].check-limit is set, mops lint skips the trimmed chain migrations to match what moc sees during mops check. To lint a trimmed migration on demand, pass an explicit filter (e.g. mops lint OldMigrationName) or --no-check-limit to lint the full chain.
mops format
mops format
mops format --check
Common Patterns
Warning suppression for a canister
Use per-canister args (not global) for suppressions:
[canisters.backend]
main = "src/backend/main.mo"
args = ["-A=M0198"]
New project
mops init -y
mops toolchain use moc latest
mops toolchain use lintoko latest
mops add core
Then configure [moc].args, [canisters], and [build] in mops.toml.
To update tools later: mops toolchain update moc or mops toolchain update (all tools).