CLI quickstartalpha
What is the shortest path from an empty directory to an installable wasm?
moxzi is a native host that runs the Motoko compiler — itself a wasm module — over your sources and writes a deployable canister module. The shortest path is three lines, and the only thing that can surprise you is that an actor must be declared persistent.
Empty directory to wasm#
mkdir demo && cd demo
printf 'persistent actor { public query func greet(n : Text) : async Text { "Hello, " # n # "!" } };\n' > hello.mo
moxzi build hello.mo -o hello.wasm
hello.mo -> hello.wasm + hello.did (220356 bytes, 1 file(s), 52 steps, 0.61s)
compiled by /…/compiler.wasm (sha256 86ea6a0c…), moxzi 0.1.0-alpha.1
You now have hello.wasm (linked, deployable) and hello.did (its candid interface). Install it with the IC SDK (dfx canister install <canister> --wasm hello.wasm), host it with moxzid, or load it into a browser tab with moxzi-web — the same bytes each time.
If -o is omitted the output takes the entry's name with a .wasm extension, so moxzi build hello.mo writes hello.wasm too.
The command surface#
There are five subcommands and no hidden sixth:
| Command | What it does |
|---|---|
moxzi build <entry.mo> | compile, then link; writes .wasm + .did |
moxzi link <unlinked.wasm> | link a module from build --no-link or from an on-chain compile |
moxzi deps <entry.mo> | print the upload closure: every file a build touches, with its VFS path |
moxzi info | which compiler and linker were loaded, their hashes, cache state, exported methods |
moxzi cache path / cache clear | the ahead-of-time compiled-module cache |
--compiler <WASM>, --linker <WASM> and --timings are global; they work on any subcommand.
The flags you will reach for first#
| Flag | Effect |
|---|---|
-o, --out <WASM> | where to write the artifact |
--debug | emit a debug build |
--no-idl | skip writing the .did |
--no-link | stop before linking; produces an unlinked, non-deployable module |
--timings | per-phase timing, plus the compiler's memory numbers |
-v, --verbose | forward the compiler's own debug output, and list the resolved closure |
--package <NAME> <PATH> | make a package available to mo:<name> imports; repeatable |
--root <DIR> | what /src maps to |
--stack-budget <N> | scheduler yield ceiling; on a large project this is minutes versus hours |
--force-gc | collect at every message boundary; expensive in instructions, free locally |
The first run is slower than the rest#
The compiler is a ~7.8 MB memory64 module. wasmtime has to compile it before it can run your code, which costs about a second — so moxzi serializes the compiled module to disk and maps it back on later runs:
moxzi cache path # /Users/you/Library/Caches/moxzi/modules
moxzi build hello.mo -o hello.wasm --timings
timings: module 0.033s (cached), sources 0.001s, instantiate 0.001s, compile 0.208s, link 0.358s (66825 -> 223251 bytes)
(cached) means the ahead-of-time cache hit; (JIT) means it did not. The cache key is the compiler bytes plus the wasmtime version plus the target, so a changed compiler, an upgraded engine, or a cache directory copied between machines can never resurrect a stale artifact. moxzi cache clear deletes it; the next build simply pays the JIT again.
Adding a second file#
Relative imports need nothing. import Greeting "lib/Greeting"; in src/Main.mo resolves against the file's own directory, and moxzi deps shows you exactly what got picked up:
moxzi deps src/Main.mo --paths-only
/pkg/base/Text.mo
/src/src/Main.mo
/src/src/lib/Greeting.mo
(abridged — mo:base/Text drags in its own imports, so the real listing is longer.)
Package imports (mo:base/Text) resolve through mops sources when there is a mops.toml, or through explicit --package NAME PATH pairs when there is not. That is the whole story, and it has its own page.
Things you cannot do#
| Why | |
|---|---|
| Compile several entry files in one invocation | moxzi build takes exactly one entry .mo; run it once per canister |
| Type-check without emitting | there is no --check; the fastest approximation is a build you throw away |
| Interpret or REPL a program | moc -r / -i have no moxzi equivalent |
| See warnings | diagnostics are printed only when the compile fails; a successful build prints only its provenance |
Deploy a --no-link module | it is unlinked by design — no runtime system, link-only exports still present |
Use --legacy-actors or --no-eop | both are retired and only print an explanatory error |
Next#
- Projects and packages — multi-file layouts, mops, and how VFS paths are decided.
- Compiling and linking — what build, link and validate each actually do.
- Coming from moc — the flag-by-flag mapping, including where moxzi deliberately differs.