DocsReference
#What a build actually costs
Measured for issue #58, 2026-09-06. The question behind it: does a managed control plane have to avoid compiling per customer? The answer is no.
Host: Mac16,5, 14 cores, rustc 1.98.1, examples/venture (core, Cloudflare runtime, Resend adapter, email-signup, waitlist, one sample module).
| Case | Wall clock | wasm |
|---|---|---|
| Cold, no cache at all | 26.7 s | 2.66 MB |
| Warm, nothing changed | 3.2 s | 2.66 MB |
| Warm, composition file touched (a module toggled) | 4.2 s | 2.66 MB |
| Warm, one new module crate added | 5.3 s | 2.69 MB |
Warm, codegen-units = 16 + opt-level = "s" | 17.3 s † | 1.86 MB |
† Confounded, and not comparable to the rows above. Changing a profile invalidates every artifact, so this number contains a full recompile caused by the measurement itself. The useful figure in that row is the size: opt-level = "s" takes 2.66 MB down to 1.86 MB, a 30% cut. Re-measure the time on a second run before drawing any conclusion about it.
#The finding
Adding one module to a warm build costs about five seconds. A cold build, with nothing cached at all, is under thirty. Compilation is not a reason to avoid anything.
Post-processing dominates, not cargo. With a warm cache, cargo build --release --target wasm32-unknown-unknown is 1.0 s unchanged and 1.3 s with a new module crate. The rest of the 4.2 s and 5.3 s is wasm-bindgen plus wasm-opt inside worker-build, and neither benefits from cargo caching. Any future effort to make builds faster belongs there, not in the compiler.
#What this means for the epic (#56)
- #59, caching the artifact on the module set, is an optimisation and not a prerequisite. It saves seconds, not minutes. Build it when there is a measured reason, not on principle. The reason to key artifacts on the module set instead of the customer remains good design; it is no longer urgent.
- Sidecar modules (#60 and after) are justified by confidentiality alone. "It avoids a rebuild" is not an argument worth making at five seconds, and no documentation or site copy should make it. The argument is that a customer can run a module we never see.
- The 1 s startup budget is not at risk: 2.66 MB parses well inside it, and
opt-level = "s"is in reserve if a large module set ever pushes on it.
#Recipe
Reproduce with a throwaway module crate, so the measurement is "one more module" and not "one more line":
- Create a crate named
module-spike-probeundercrates/implementingModulewithrequires()empty,Migrations::EMPTY, and a router with oneGET /ping. Nothing else; the point is to measure linking a crate, not compiling a feature. It is deliberately not checked in — a crate that exists is a crate the build pays for. cargo clean, thenworker-build --releaseinexamples/venturefor the cold row.- Re-run untouched for the warm row;
touch src/lib.rsfor the toggle row. - Add the probe crate as a path dependency and
.module(SpikeProbe::new())to the composition for the new-module row. - Time
cargo build --release --target wasm32-unknown-unknown -p ventureseparately to split compilation fromwasm-bindgenandwasm-opt.
Use the rustup toolchain explicitly (~/.cargo/bin/cargo). A Homebrew rustc on PATH shadows it and is too old for this workspace's edition.
#Re-measured 2026-09-07
Same host and method, examples/venture as it stands after the UI epic (#69). The binary has grown; the build has not become a problem.
| Case | wasm |
|---|---|
| 2026-09-06, as measured above | 2.66 MB |
| Today, without the UI renderer mounted | 2.98 MB |
| Today, as shipped | 3.50 MB |
cratefield-ui and its ui.json account for 0.52 MB of that, measured by dropping the .ui(..) call and the dependency and rebuilding. The 0.32 MB between the two older figures is everything else landed since: schemars for the module surface, the sidecar dispatcher and mount, the admin pages.
Nothing here changes the finding above: a warm build with a new module crate is still seconds. If the size ever matters — a cold-start budget, not a build budget — opt-level = "s" is the first lever, and mounting the UI is optional per venture.
Mirrored from docs/BUILD-COST.md at b6f50cd. The harness is the source of truth: a correction goes there first.