V8-based ECMAScript runtime for the server. WinterTC-compliant, capability secured.
import { serve } from "runtime:http";
const server = serve({ port: 8080 }, (req) => {
return new Response("👋 Hello from ESRun!");
});
const { hostname, port } = await server.addr;
console.log(`listening on http://${hostname}:${port}`);
fetch, URL, URLPattern, streams, WebCrypto, encoding, timers, and events — the WinterTC Minimum Common Web Platform API. What you learn here is what runs in the browser.
HTTP and WebSocket servers, filesystem, sockets, subprocesses, WASM/WASI, and XML, YAML, TOML, JSONL, MessagePack, and Protobuf parsers — all behind runtime: imports, nothing to install.
Static imports, dynamic import(), top-level await, import.meta, and JSON modules. One module system, no CommonJS interop rules to learn — esdev's bundler converts a CJS dependency at build time.
The runtime around the engine is safe Rust: no data races, no use-after-free, no buffer overruns to reach for under hostile input.
The engine behind Chrome and Node.js, embedded from Rust. A baked startup snapshot opens a full realm in about 9 ms.
Deny-by-default: a run reaches what the command line that started it named, and nothing else. Every host operation is gated on an explicit capability, checked in Rust rather than in JavaScript.
Choosing a runtime? How esrun compares to Node.js, Bun and Deno →
Durable workers: addressable state that outlives the process.
Calls to one worker queue and run in order, so two customers cannot both take the last item. No lock to take, no row to contend for.
A result is released only after the writes behind it have committed. A crash is a call that never returned, never one that returned a lie.
An alarm is stored beside the state and runs after a restart: retries, abandoned carts, a nightly roll-up, without a scheduler service.
State lives in embedded SQLite, one file per worker, under the same read and write grants as everything else. No Redis, no queue, no database server.
Killed with SIGKILL under load, the example shop loses no order it acknowledged.
Plaintext hello-world over loopback, driven by oha at 100 connections — best of three runs. Elysia is measured on the esdev bundle every runtime serves (esrun is ESM-only), and Node serves both frameworks through the same @hono/node-server glue, so the delta is route handling, not the adapter. How it is measured →
A run reaches what the command line named, and nothing else.
Nine capabilities: read, write, imports, net, listen, env, run, signals, workers. The gate is the op, not the import.
esrun runs your service and nothing else — no watcher, no debugger port, no transform. That narrowness is what a capability flag is worth.
esdev pays for it on your machine: same runtime, same flags, plus the toolchain to get there.
esdev, not in productionInstall both binaries with one command, and run your first module. Standards-based, fast, ESM-only.
Nothing is granted unless the command line says so. Build the deploy line that states exactly what your service may touch.