Skip to content

System Overview

Thunder is a Rust-powered edge runtime built on the Deno stack. It compiles to a single binary (thunder) that starts an HTTP server with two listeners: an ingress listener for user-facing traffic and an admin listener for operator-level management. Both listeners share a common function registry backed by an in-process isolate pool.

graph LR
Client["Client"]
Operator["Operator"]
Ingress["Ingress Listener"]
Admin["Admin Listener"]
Registry["Function Registry"]
Pool["Isolate Pool"]
Isolate["V8 Isolate"]
Handler["JS/TS Handler"]
Response["Response"]
Client --> Ingress
Ingress --> Registry
Registry --> Pool
Pool --> Isolate
Isolate --> Handler
Handler --> Response
Response --> Client
Operator --> Admin
Admin -->|deploy / manage| Registry

User traffic arrives at the ingress listener, which resolves the target function from the request path, looks it up in the function registry, and dispatches the request to a V8 isolate drawn from the pool. The isolate executes the JavaScript or TypeScript handler and streams the response back to the client.

Operators interact with the admin listener to deploy new functions, update existing ones, or query runtime status. The admin listener writes directly to the function registry, which in turn manages the lifecycle of isolate pools.

ComponentTechnologyVersion
LanguageRust2021 edition
Async runtimeTokio1.36+
JavaScript engineV8 (via deno_core)deno_core 0.390.0
HTTP serverHyper1.4.1
TLSRustls0.23.11
Module bundlingESZIP0.109.0
TelemetryOpenTelemetry0.27.0

The V8 JsRuntime type is !Send, which means it cannot be moved between threads. Thunder respects this constraint by spawning a dedicated OS thread for each isolate. Async I/O still runs on the Tokio runtime, but the V8 event loop is driven on its own thread. This avoids unsafe hacks and makes the ownership model explicit.

Rather than forking processes or communicating over IPC, Thunder keeps all isolates in the same process and manages them through a pooling layer with LRU eviction. This eliminates serialization overhead on the hot path and allows sub-millisecond dispatch for warm requests.

Functions are deployed as ESZIP bundles — a compact, seekable archive format designed by the Deno project. ESZIPs contain pre-resolved module graphs (including source maps and TypeScript type-stripped sources), which means the runtime can skip module resolution at load time and go straight to V8 compilation. This dramatically reduces cold-start latency compared to on-the-fly transpilation.