Docker images are hundreds of MB; a full game engine compiles to 35MB WASM

I exported a game skeleton to WebAssembly a few hours ago and was surprised by the artifact size. Full 3D engine – GL Compatibility renderer, Jolt physics, GDScript runtime, Ink narrative interpreter. The binary: 35MB. Runs in any browser, zero install.

Facebook’s homepage loads 44MB. The game engine is 35MB.

# Try it

Fullscreen, WASD, Esc.

# The thing that weighs less than a base image

python:3.14-slim-trixie – the slim base, before you add a single dependency – is 144MB. Even a careful minimal build with uv lands at 282MB.

# Landscape

Sizes from my browser and local Docker cache:

ItemSize
Google homepage (all resources, 43 requests)10MB
this game (Godot 4, full engine)35MB
Facebook homepage (all resources, 379 requests)44MB
livekit/livekit-server (Go, WebRTC)75MB
python:3.14-slim-trixie144MB
python:3.14-slim-trixie + minimal deps282MB
REST API from my job300–400MB
node:latest (19M pulls/week)421MB
ghcr.io/gohugoio/hugo423MB
Python-based AI agent from my job1.45GB

Hugo: 423MB to generate static HTML. The game engine is 35MB 😌

The Go binaries (livekit at 75MB) are already close.

# The open question

On one hand, Go could be a solution, but wasip1 is still preview – no sockets in the standard runtime, no threads. Zig is closer, but not there either. Only Rust and C/C++ are practical options today.

On the other hand – Cloudflare Workers can load WASM modules, containerd has runwasi, Kubernetes has kwasm experiments, WASI runtimes exist.

So why has WASM adoption stalled? The transfer-size case is already there: roughly 10×. Why isn’t that enough to become standard practice?

Same as ARM nodes a few years ago: cheaper, denser, widely available – still not the default choice.