Field Guide · 10 Languages · 30 Runtimes

The runtime
Royal Rumble, every language is a weight class.

A language is a spec — text that promises what map or async mean. A runtime is whatever is actually there at the moment your code executes: translating source to instructions, managing memory, scheduling work, and binding to the world outside the CPU. Many languages have several. Click any card.

10
Languages
30
Runtimes
04
Axes
∞
Trade-offs
00 — Axes

Four questions every runtime must answer.

The personality of any runtime is mostly determined by how it resolves these four. Hold them in mind as you read the rest — they're what makes Bun feel different from Node, or HotSpot different from GraalVM.

01 · EXECUTION

How does source become CPU work?

Interpret bytecode directly, JIT-compile hot paths at runtime, or AOT-compile everything before shipping. Each is a different gamble on startup time vs. peak throughput.

02 · MEMORY

Who decides when to free?

Tracing GC, reference counting, ownership-based, or manual. Determines latency profile, fragmentation, and whether you ever say the words "stop the world."

03 · CONCURRENCY

How is work scheduled?

OS threads, green threads, goroutines, fibers, event loops, actors. Where the parallelism comes from and what synchronisation costs.

04 · CAPABILITIES

What slice of the world is reachable?

Filesystem, sockets, DOM, GPU, kernel-side hooks, edge KV stores. The runtime decides what the language can do, far more than the language itself.

01 — Language

JavaScript / TypeScript

ECMAScript deliberately defines very little: Array, Promise, async/await. Everything else — fetch, setTimeout, fs.readFile, document — is provided by the host. That's why the same language behaves so differently in a browser vs. a server vs. an edge worker. Each is a distinct ambient world bolted onto an engine.

Engines V8 · JSC · SpiderMonkey · Hermes
02 — Language

Python

Python the language is one thing; Python the runtime is a choice. CPython is the reference and what most people use; PyPy is the same language with a JIT instead of a bytecode interpreter; MicroPython is the same language with the standard library mostly torn out so it can fit on a microcontroller. The differences are dramatic — performance, threading semantics, C-extension compatibility all flip depending on which one you boot.

Spec PEP-driven · CPython ref
03 — Language family

JVM bytecode — Java, Kotlin, Scala, Clojure

Unusually, the runtime here is shared by an entire family of languages. They all compile to JVM bytecode, then a JVM executes it. So Kotlin's pauses, Scala's reflection, and Clojure's startup time are really HotSpot's pauses, HotSpot's reflection, HotSpot's startup. Picking GraalVM or OpenJ9 changes all of those without touching a line of source.

Bytecode JVMS · stack-based
04 — Language family

.NET / CIL — C#, F#, VB.NET

The Microsoft counterpart to the JVM. Source compiles to CIL (Common Intermediate Language), and a CLR executes it. Modern .NET has unified what used to be three forks: CoreCLR for server, Mono for mobile and games, and NativeAOT for trim-down deployments where you want zero JIT. Same language surface, three different runtime experiences.

Bytecode CIL · ECMA-335
05 — Language

Go

Go has effectively one runtime, but it's an unusual one: it's compiled into every binary. No VM to install, no JIT to warm up. Yet that statically-linked binary contains a goroutine scheduler, a concurrent GC, channels, and a network poller — all running invisibly underneath your main(). The pitch was "deploy a single file"; the design consequence is that every Go program ships with a few megabytes of runtime even for hello-world.

Distribution static binary · ahead-of-time
06 — Language

Rust

Rust is the clarifying counter-example. People say it has "no runtime" because nothing tracks references at execution time and no scheduler is mandatory — ownership is checked at compile time and goes away before the program runs. But that's only true for synchronous Rust. The moment you write async fn, you need a runtime to drive the futures, and you pick one. Tokio, async-std, smol — same language, three different worlds.

Memory ownership · no GC
07 — Language family

BEAM — Erlang, Elixir, Gleam

Most runtimes start from "execute the language." BEAM started from "build a phone switch that never goes down." Everything else — millions of lightweight processes, per-process GC, hot code reloading, transparent network distribution — falls out of that founding constraint. Three languages now ride on it; they share the runtime's superpowers and its quirks (no shared memory, weird-looking pattern matching at every boundary).

Origin Ericsson · 1986
08 — Language

Ruby

Ruby spent a decade as a pure interpreter (MRI), then YARV gave it a real bytecode VM, then YJIT gave it a JIT. Each step roughly halved the gap to V8. TruffleRuby — Ruby on GraalVM's polyglot stack — closes the rest in some benchmarks. It's a useful demonstration that "the language is slow" is almost always shorthand for "the dominant runtime hasn't caught up yet."

VM YARV · YJIT (Shopify)
09 — Language

Lua

Lua exists because the original authors needed a tiny scripting language they could embed in other programs. That constraint produced a runtime that fits in a few hundred kilobytes — and which now lives inside Nginx, Redis, World of Warcraft, Roblox, and Neovim. Then Mike Pall wrote LuaJIT and turned this small embeddable thing into one of the fastest dynamic-language implementations ever built. Same language, two extraordinarily different engines.

Footprint ~200 KB embeddable
10 — Language target

WebAssembly — Rust, C, Go, Zig, AssemblyScript

Wasm isn't a language people write directly — it's a binary instruction format that other languages compile to. The interesting thing is that this turns "runtime" into a commodity: any host that implements the Wasm spec can run the same bytecode. The browser was first; standalone runtimes (Wasmtime, Wasmer) followed; edge platforms (Fastly, Fermyon) bet the whole product on it. Cold starts in microseconds because the verifier replaces the trust model that VMs usually need.

Spec W3C Wasm · WASI
Back to JIT-Atlas