[RSCH] 7 min readOraCore Editors

WebAssembly-to-C still rivals native runtimes in 2026

Frank DENIS found WebAssembly-to-C still matches top runtimes on 2026 libsodium tests, even after new wide arithmetic support.

Share LinkedIn
WebAssembly-to-C still rivals native runtimes in 2026

WebAssembly-to-C still matches top runtimes on 2026 libsodium benchmarks.

Frank DENIS ran a fresh 2026 benchmark and found that compiling WebAssembly to C can still keep up with dedicated runtimes on real code. The surprising part is that this held even after WebAssembly runtimes got better compilers, better lowering, and wider instruction support.

That result comes from a specific setup: Frank DENIS compared Wasmer 7.1.0, Wasmtime 46.0.0, and WABT’s wasm2c path on the same libsodium benchmark suite. He also added support for the wide arithmetic proposal in his wasm2c fork, then built the generated C with zig cc using -O3 -march=native.

ItemValueWhy it matters
Wasmer version7.1.0One of the comparison runtimes
Wasmtime version46.0.0Another comparison runtime
Build flagslime1 + simd128 + wide_arithmeticFeature set used for every build
Compilerzig cc -O3 -march=nativeNative C compilation path
Runtime memory sampling15 runs, median RSSHow memory usage was measured

The benchmark result that changed the argument

Get the latest AI news in your inbox

Weekly picks of model releases, tools, and deep dives — no spam, unsubscribe anytime.

No spam. Unsubscribe at any time.

DENIS said he expected the case for WebAssembly-to-C to weaken over time. That seemed reasonable. Runtime engines keep improving, and modern JITs have more room to optimize than a simple transpiler can.

WebAssembly-to-C still rivals native runtimes in 2026

The 2026 numbers pushed the other way. On the benchmark he used, the wasm2c path performed very well and beat the newer runtimes once wide arithmetic was in play. In his write-up, the median was a tie with Wasmer, while wasm2c used 0.887x as much time as Wasmer on the geomean and 0.814x as much as Wasmtime.

  • Median result: tied with Wasmer
  • Geomean runtime: wasm2c at 0.887x Wasmer
  • Geomean runtime: wasm2c at 0.814x Wasmtime
  • Benchmark target: libsodium

That is a useful reminder for anyone who treats “runtime” as the default answer. If the WebAssembly module is known ahead of time, and if you can precompile it, a normal native compiler can still do a very good job on the generated C.

Why the C path still works

The big reason is simple: the output is ordinary C. That means the final codegen step is handled by a mature native compiler, not by a small custom backend. DENIS also notes that the wide arithmetic implementation in wasm2c was surprisingly easy to add, relying on compiler carry intrinsics and C’s 128-bit integer type.

There is also an operational upside. A WebAssembly runtime brings engine code, startup state, and JIT machinery into the process. A C-compiled module does not. DENIS measured peak resident set size with /usr/bin/time -v and found that most of the runtime footprint is fixed engine overhead, while the module itself is cheap.

“The best WebAssembly runtime may still be no runtime at all.” — Frank DENIS

That quote is the whole thesis in one line. If you already have the module and you do not need runtime services, the extra layer may be more machinery than value.

Memory matters more than people admit

DENIS used cold process RSS, measured as the median of fifteen runs, to compare memory use. He also points out that some of the cost from Wasmer and Wasmtime can be amortized if a service keeps the engine warm and runs many modules or many calls. For one-shot jobs, though, cold-start overhead matters a lot.

WebAssembly-to-C still rivals native runtimes in 2026

That distinction is why these results should be read carefully. A runtime can be the right call in a server that keeps a process alive for hours. A precompiled C path can win in batch jobs, short-lived CLI tools, and deployment environments where shipping an engine is awkward.

  • Measurement method: cold RSS from /usr/bin/time -v
  • Run count: 15 per configuration
  • Module memory cap: 64 MiB maximum linear memory
  • Overhead source: engine executable plus startup state

In other words, the benchmark is not saying runtimes are bad. It is saying the economics change once startup and engine size enter the picture.

What this means for deployment choices

WebAssembly-to-C also changes the deployment target. The destination machine no longer needs a WebAssembly runtime. It needs a C compiler and enough libc support for the module’s imports. That makes the output portable in a very old-fashioned, very practical way.

DENIS also points out that the compiler is now a choice. You can use clang or GCC, or you can pick a toolchain with a different trust model. He mentions Fil-C for memory safety on wasm64 or wasm32 without depending on virtual-memory guard pages, and CompCert for verified code generation.

That flexibility is a real advantage. A dedicated runtime gives you one execution model. WebAssembly-to-C lets you choose the compiler and, by extension, the tradeoff you want between speed, safety, and assurance.

Where Wasmer and Wasmtime still win

This is also where the article gets more nuanced. DENIS is clear that WebAssembly-to-C is the wrong answer for dynamic loading of untrusted code, runtime policy enforcement, preemption, fuel metering, component-model machinery, or multi-tenant execution on one shared engine.

He also gives credit where it is due. Wasmer implements WASIX, which fills in many POSIX-shaped gaps that plain WASI still leaves open. If your goal is to run existing applications with fewer rewrites, that is a much more direct path than transpiling to C.

Wasmtime also matters because of the Component Model, which gives WebAssembly pieces typed boundaries for composition. DENIS says a similar effect might be possible by compiling components separately to C, but he did not explore that deeply.

That leaves a pretty clear split. Use a runtime when you need runtime services. Use WebAssembly-to-C when you control the module, can precompile it, and want the smallest possible execution stack.

  • Best fit for runtimes: untrusted code, policy, fuel, multi-tenant hosting
  • Best fit for WebAssembly-to-C: controlled modules, precompilation, short-lived jobs
  • Wasmer strength: WASIX support for POSIX-like workloads
  • Wasmtime strength: Component Model support for typed composition

The practical takeaway for engineers

The real lesson here is that WebAssembly has grown in two directions at once. Runtime engines got better, but the “compile to C first” path did not fall behind as much as many people assumed. Once wide arithmetic landed, it remained competitive on a benchmark that matters to systems programmers: cryptographic code with real performance pressure.

If you are shipping WebAssembly today, the best default is still not a slogan. It depends on whether you need an engine, whether you trust the code, and whether the module must run unchanged across hosts. If those answers are yes, use a runtime. If they are no, WebAssembly-to-C is still a very serious option.

The next question worth asking is simple: how much of your WebAssembly workload actually needs a runtime once wide arithmetic, component splitting, and modern C toolchains are all on the table?