The disk column is grounded in the actual binaries on the box; the boot and memory columns come from this project's measured numbers. The relay itself is identical across every row — only the platform underneath changes.
| Model | Disk image | Memory (working set) | Boot: OS | Boot: app | Cold → serving |
|---|---|---|---|---|---|
| Container Docker / Kubernetestypical | ~60–120 MB | ~30–50 MB | 0shares host kernel | ~ms | ~tens of ms1 |
| microVM + full Linux e.g. fly.io / Firecrackertypical | ~100–150 MB | ~50–100 MBVMs sized 256 MB–1 GB | ~100–125 ms | ~ms | ~125–175 ms |
| Unikraft binary-compat mode2measured here | ~40–55 MB | ~63 MB | ~38–39 ms | ~43 ms | ~82 ms |
| Unikernel, native TinyMoQmeasured here | 11.5 MB | ~19 MB | ~15 ms | ~1 ms | ~35 ms |
ld-linux at runtime); the native unikernel image = 11.5 MB (fully static, nothing else needed). The host-side VMM is separate from the guest image and isn't counted in these figures.
1 Cold → serving excludes orchestration (image pull / scheduling), which adds seconds.
2 Unikraft also supports native (compiled-in) builds, which are substantially smaller and faster than the binary-compat figures shown here. This row reflects Unikraft running the unmodified Linux binary. Reaching those native figures is specialized work, not a recompile: the relay must be built against Unikraft's native API (no Linux syscall shim), and QUIC's UDP datapath and async runtime need low-level fixes in the kernel's socket and scheduler — the porting work we focus on.
It's where the models diverge by ~100×: containers pay 0 (shared kernel), the native unikernel ~15 ms, a binary-compat unikernel ~39 ms, full-Linux microVMs ~100–125 ms. App init is ~1–few ms everywhere — it's the same relay; the platform doesn't change it.
Native unikernel ~19 MB vs binary-compat unikernel ~63 MB vs full-Linux microVM ~50–100 MB+. That's the density lever — roughly 3–5× more relays per host than a full-Linux microVM.
The native unikernel compiles the relay straight into the kernel image → one 11.5 MB static binary with no external dependencies. Unikraft in binary-compat mode runs the unchanged 40 MB Linux binary on a loader shim → bigger and still glibc-dependent. (That 40 MB binary is unstripped; stripping roughly halves it, but it still needs glibc — the native image needs nothing.)
Containers and microVMs run the stock Linux binary (zero porting — what fly.io / Kubernetes do); the unikernel rows required compiling/porting the relay and fixing low-level bugs. The table compares the artifacts, not the effort.