Clojure runs in a lot of places now. Each runtime below was built for a different job and is excellent at it. This page is a map of where they sit, not a ranking — ClojureWasm is one young entry exploring the WebAssembly corner, and the only numbers it claims are its own measured ones.
| Runtime | Host / where it shines | Distribution |
|---|---|---|
| Clojure (JVM) | The JVM. Mature, complete, an enormous ecosystem. | Runs on a JVM. |
| Babashka / SCI | GraalVM native / JS. Fast-starting scripting, glue. | Self-contained binary. |
| ClojureScript | JavaScript. Front-end and the Node ecosystem. | JS host. |
| jank | LLVM / C++. Native code and seamless C++ interop. | Native. |
| ClojureDart | Dart / Flutter. Mobile and cross-platform UI. | App bundles. |
| jolt | Chez Scheme. A self-hosted compiler to native code, and C-ABI shared libraries. | Self-contained binary. |
| clojurust | Rust. Cranelift JIT, AOT to native, Rust libraries as cdylib plugins. |
Native binary. |
| ClojureWasm | Zig. Embeds a Wasm engine so Clojure calls modules from Rust/Go/C (polyglot FFI). | ~8.1 MB native binary, starts in ~6 ms. |
The other rows are respectful summaries of what each runtime is known for, not evaluations. The ClojureWasm row lists only its own measured figures; it does not claim to beat anything.
Two things, which are easy to conflate — and only the first one is shipped:
- ClojureWasm embeds a WebAssembly engine. A Clojure program can load a
sandboxed module compiled from Rust, Go, Zig, or C and call it like a
namespace. WebAssembly becomes an FFI: other languages' libraries become
callable from Clojure, in-process and sandboxed. (See
docs/examples/wasm/.) This is the angle ClojureWasm is exploring, and it has no obvious equivalent in the other runtimes. - ClojureWasm does not ship as a
.wasm. The runtime compiles forwasm32-wasi, and CI keeps that target compiling, but no release carries the artifact. That build is single-threaded: no futures or agents, no network, nocljw.ffi, no embedded engine.cljw buildproduces a native binary with an embedded bytecode payload, not a.wasm. The value representation and garbage collector use linear memory, so the build does not interoperate with WasmGC-based languages.
Compiling Clojure source into a WebAssembly component is a separate project: ClojureWit, in the upstream org.
clojurust is a Rust-hosted Clojure dialect by the same maintainer, with a Cranelift JIT and native AOT. Neither hosts the other (cljrs cannot host a component), but they share three things:
-
The C FFI.
cljw.ffiandclojure.rust.ffiare one API overdlopen, so a portable adapter is one reader conditional (docs/examples/ffi/). -
The Clojure surface. cljw reads
.cljcunder{:cljw :clj :default}and cljrs under{:rust}, so a host-free.cljcruns unchanged on the JVM, on cljw and on cljrs. Conditionals are needed only where a kernel touches a host. jolt runs the same file too (measured); it also reads:clj, so its:joltbranch goes before:clj. -
The Rust library. The same crate serves cljw as a zero-import Wasm component and cljrs as a native
cdylib. Measured on a Groth16 prover (2026-09-12): identical 128-byte proofs and verdicts on both; cljrs ran it in 1.29 s (debug build) with 212 environment variables, the filesystem and the clock in reach, cljw in 9.17 s with none of them. A program chooses speed or confinement per deployment, without a rewrite; the per-runtime adapter absorbs shape differences (a WITresultlifts to[:ok v]/[:err e], a trap reports as the capability answer it is) and the shared program keeps the semantics.
ClojureWasm is a host. It loads two kinds of foreign code:
- Wasm modules and WIT components, sandboxed, under a fuel and memory
budget (
cljw.wasm). - Native shared libraries, unsandboxed, through
dlopen(cljw.ffi).
It is not yet a guest. cljw build produces an executable and there is no
shared-library build, so a C, Rust or .NET program cannot link it. The
wasm32-wasi build above is the one route in: any Wasm host could run it,
cljw included, but it is unreleased.
jolt covers that direction:
jolt build --library compiles a Clojure project into a shared object with
its runtime inside, entered through jolt_library_init and jolt_lookup.
The two meet at the C ABI. A jolt library is native code with ambient
authority, so it loads through cljw.ffi, not through the sandbox.
examples/ffi/jolt calls one: ffi/function-at over the pointers jolt_lookup returns.
Babashka and SCI made JVM-free Clojure scripting fast and ordinary; jank is doing the hard work of native Clojure with C++ interop; ClojureDart put Clojure on Flutter; ClojureScript has carried Clojure on the front-end for over a decade; and the JVM remains the complete, production-proven home of the language. ClojureWasm exists because of the path those projects cleared, and it is exploring one more corner — not competing for the others' ground.
- Runtime descriptions: each project's own README / site (Clojure, Babashka, ClojureScript, jank, ClojureDart, jolt, clojurust).
- ClojureWasm figures:
bench/RELEASE_METRICS.md(reproduce withbash bench/release_metrics.sh). - ClojureWasm compatibility detail:
docs/clojure_vs_clojurewasm.mdanddata/compat_tiers.yaml.