moxzi
Docs / CLI / CLI quickstart

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:

CommandWhat 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 infowhich compiler and linker were loaded, their hashes, cache state, exported methods
moxzi cache path / cache clearthe 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#

FlagEffect
-o, --out <WASM>where to write the artifact
--debugemit a debug build
--no-idlskip writing the .did
--no-linkstop before linking; produces an unlinked, non-deployable module
--timingsper-phase timing, plus the compiler's memory numbers
-v, --verboseforward 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-gccollect 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 invocationmoxzi build takes exactly one entry .mo; run it once per canister
Type-check without emittingthere is no --check; the fastest approximation is a build you throw away
Interpret or REPL a programmoc -r / -i have no moxzi equivalent
See warningsdiagnostics are printed only when the compile fails; a successful build prints only its provenance
Deploy a --no-link moduleit is unlinked by design — no runtime system, link-only exports still present
Use --legacy-actors or --no-eopboth are retired and only print an explanatory error

Next#

On this pageEmpty directory to wasmThe command surfaceThe flags you will reach for firstThe first run is slower than the restAdding a second fileThings you cannot doNext