Alpha

A secure, standards-based server runtime.

V8-based ECMAScript runtime for the server. WinterTC-compliant, deny-by-default, and everything a service needs in one binary.

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}`);

Benchmarks

Hono hello-world · Speed & Memory
Runtime
Throughput (higher ↑)
Memory (lower ↓)
Bun
80.0k
50 MB
Deno
79.0k
72 MB
esrun
53.7k
46 MB
Node.js
32.7k
128 MB
Cold start (near-empty script)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
11.2ms
22MB
Deno
24.5ms
54MB
esrun
8.1ms
24MB
LLRT
3.4ms
11MB
Node.js
17.9ms
41MB
Parse + run ~100 KB script
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
24.2ms
26MB
Deno
33.9ms
55MB
esrun
20.3ms
24MB
LLRT
11.7ms
11MB
Node.js
29.5ms
40MB
Load a 300-module graph
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
28.2ms
32MB
Deno
41.9ms
57MB
esrun
25.2ms
25MB
LLRT
14.2ms
11MB
Node.js
82.3ms
58MB
Peak resident memory (idle)
Runtime
Perf (lower is better)
Bun
22MB
Deno
54MB
esrun
24MB
LLRT
11MB
Node.js
41MB
Peak resident memory (under load)
Runtime
Perf (lower is better)
Bun
160MB
Deno
147MB
esrun
120MB
LLRT
156MB
Node.js
131MB
Tight compute loop
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
112.9ms
34MB
Deno
218.1ms
62MB
esrun
244.6ms
34MB
LLRT
2283.1ms
11MB
Node.js
199.1ms
50MB
JSON parse/stringify
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
195.7ms
90MB
Deno
210.3ms
78MB
esrun
191.3ms
49MB
LLRT
682.8ms
11MB
Node.js
286.6ms
76MB
JSON (large documents)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
514.3ms
138MB
Deno
542.2ms
160MB
esrun
542.7ms
133MB
LLRT
1799.9ms
128MB
Node.js
710.7ms
155MB
Regex (match, validate, replace)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
22ms
47MB
Deno
64.2ms
64MB
esrun
63.2ms
35MB
LLRT
1296.2ms
11MB
Node.js
67.3ms
52MB
String building and slicing
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
79.2ms
111MB
Deno
61.2ms
72MB
esrun
59ms
43MB
LLRT
156.1ms
11MB
Node.js
60.7ms
60MB
structuredClone
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
283.3ms
82MB
Deno
265ms
67MB
esrun
279.1ms
45MB
LLRT
335.3ms
11MB
Node.js
224.2ms
51MB
throw/catch + stack capture
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
359.5ms
123MB
Deno
4373.1ms
95MB
esrun
385.1ms
43MB
LLRT
323.9ms
11MB
Node.js
1472.5ms
60MB
async/await throughput
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
51.6ms
67MB
Deno
32.8ms
64MB
esrun
30ms
36MB
LLRT
687.9ms
11MB
Node.js
58.3ms
51MB
setTimeout churn
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
30.4ms
59MB
Deno
205.5ms
187MB
esrun
54.4ms
57MB
LLRT
47.1ms
42MB
Node.js
40.1ms
84MB
URL parsing
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
72.5ms
86MB
Deno
103.7ms
71MB
esrun
87.3ms
42MB
LLRT
112.3ms
11MB
Node.js
48.7ms
60MB
TextEncoder/TextDecoder (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
21.5ms
59MB
Deno
65.5ms
74MB
esrun
76.9ms
44MB
LLRT
69.3ms
11MB
Node.js
65ms
62MB
TextEncoder/TextDecoder (64 KiB)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
65.1ms
63MB
Deno
226.3ms
63MB
esrun
277.8ms
35MB
LLRT
207.9ms
11MB
Node.js
296ms
51MB
base64 (atob/btoa)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
13.3ms
57MB
Deno
7.4ms
65MB
esrun
22.3ms
34MB
LLRT
32.5ms
11MB
Node.js
6.7ms
51MB
TypedArray / DataView
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
19.7ms
51MB
Deno
12.5ms
64MB
esrun
12.2ms
36MB
LLRT
70.1ms
11MB
Node.js
13.7ms
52MB
Headers / Request parsing
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
261.1ms
87MB
Deno
1504.5ms
148MB
esrun
409.8ms
46MB
LLRT
713ms
11MB
Node.js
425.3ms
71MB
Multipart FormData round trip
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
18.8ms
57MB
Deno
366.9ms
101MB
esrun
83.9ms
41MB
LLRT
1331.2ms
11MB
Node.js
291.2ms
116MB
Date + Intl formatting
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
74.7ms
52MB
Deno
132.2ms
69MB
esrun
131.1ms
40MB
LLRT
Node.js
122.7ms
59MB
ReadableStream piping
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
8.1ms
38MB
Deno
13.7ms
67MB
esrun
10ms
40MB
LLRT
Node.js
21.9ms
57MB
SubtleCrypto SHA-256
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
422.4ms
41MB
Deno
487.5ms
67MB
esrun
327.2ms
32MB
LLRT
324.4ms
11MB
Node.js
503.5ms
55MB
HMAC + AES-GCM
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
77.4ms
37MB
Deno
129ms
66MB
esrun
33.6ms
33MB
LLRT
24.5ms
11MB
Node.js
147.6ms
54MB
ECDSA P-256 sign + verify
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
188.8ms
33MB
Deno
2170.6ms
67MB
esrun
1092.2ms
32MB
LLRT
1012.8ms
11MB
Node.js
306.1ms
55MB
PBKDF2 (10k iterations)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
64.2ms
27MB
Deno
70.4ms
55MB
esrun
96.8ms
25MB
LLRT
97.7ms
11MB
Node.js
71.1ms
45MB
fetch (local server)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
17.5ms
32MB
Deno
32.9ms
63MB
esrun
39.1ms
36MB
LLRT
17.1ms
11MB
Node.js
82.8ms
87MB
File read (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
35.5ms
39MB
Deno
38.1ms
63MB
esrun
38.8ms
39MB
LLRT
26ms
11MB
Node.js
111.2ms
53MB
File read (large)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
23.5ms
89MB
Deno
61.2ms
187MB
esrun
42.4ms
95MB
LLRT
12.5ms
13MB
Node.js
56.5ms
111MB
File write (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
12.2ms
34MB
Deno
84.5ms
62MB
esrun
72.4ms
31MB
LLRT
96.2ms
11MB
Node.js
154.9ms
53MB
File write (large)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
18.9ms
34MB
Deno
40.2ms
101MB
esrun
57.8ms
31MB
LLRT
50.4ms
15MB
Node.js
57.2ms
90MB
File append (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
29.8ms
35MB
Deno
38.7ms
63MB
esrun
30ms
30MB
LLRT
Node.js
100.2ms
54MB
File append (large)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
6.7ms
31MB
Deno
15.7ms
71MB
esrun
18.2ms
26MB
LLRT
Node.js
22.7ms
57MB
File stat (one path)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
49.7ms
35MB
Deno
85.8ms
60MB
esrun
65.3ms
32MB
LLRT
41.5ms
11MB
Node.js
68.9ms
47MB
File stat (1000 paths)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
195.7ms
40MB
Deno
361ms
67MB
esrun
283.6ms
37MB
LLRT
173.8ms
11MB
Node.js
268.4ms
58MB
File exists (one path)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
7.1ms
36MB
Deno
87.9ms
61MB
esrun
51.1ms
31MB
LLRT
48ms
11MB
Node.js
64.8ms
47MB
File exists (1000 paths)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
30.5ms
47MB
Deno
356.1ms
68MB
esrun
224.7ms
32MB
LLRT
195.5ms
11MB
Node.js
253.1ms
58MB
Glob scan
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
28.8ms
47MB
Deno
esrun
49ms
33MB
LLRT
Node.js
182ms
64MB
Spawn a child process
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
95.3ms
47MB
Deno
103.2ms
71MB
esrun
75.6ms
32MB
LLRT
89.4ms
11MB
Node.js
197.1ms
50MB
Cold start (near-empty script)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
11.2ms
22MB
Deno
24.5ms
54MB
esrun
8.1ms
24MB
LLRT
3.4ms
11MB
Node.js
17.9ms
41MB
Parse + run ~100 KB script
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
24.2ms
26MB
Deno
33.9ms
55MB
esrun
20.3ms
24MB
LLRT
11.7ms
11MB
Node.js
29.5ms
40MB
Load a 300-module graph
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
28.2ms
32MB
Deno
41.9ms
57MB
esrun
25.2ms
25MB
LLRT
14.2ms
11MB
Node.js
82.3ms
58MB
Peak resident memory (idle)
Runtime
Perf (lower is better)
Bun
22MB
Deno
54MB
esrun
24MB
LLRT
11MB
Node.js
41MB
Peak resident memory (under load)
Runtime
Perf (lower is better)
Bun
160MB
Deno
147MB
esrun
120MB
LLRT
156MB
Node.js
131MB
Tight compute loop
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
112.9ms
34MB
Deno
218.1ms
62MB
esrun
244.6ms
34MB
LLRT
2283.1ms
11MB
Node.js
199.1ms
50MB
JSON parse/stringify
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
195.7ms
90MB
Deno
210.3ms
78MB
esrun
191.3ms
49MB
LLRT
682.8ms
11MB
Node.js
286.6ms
76MB
JSON (large documents)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
514.3ms
138MB
Deno
542.2ms
160MB
esrun
542.7ms
133MB
LLRT
1799.9ms
128MB
Node.js
710.7ms
155MB
Regex (match, validate, replace)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
22ms
47MB
Deno
64.2ms
64MB
esrun
63.2ms
35MB
LLRT
1296.2ms
11MB
Node.js
67.3ms
52MB
String building and slicing
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
79.2ms
111MB
Deno
61.2ms
72MB
esrun
59ms
43MB
LLRT
156.1ms
11MB
Node.js
60.7ms
60MB
structuredClone
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
283.3ms
82MB
Deno
265ms
67MB
esrun
279.1ms
45MB
LLRT
335.3ms
11MB
Node.js
224.2ms
51MB
throw/catch + stack capture
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
359.5ms
123MB
Deno
4373.1ms
95MB
esrun
385.1ms
43MB
LLRT
323.9ms
11MB
Node.js
1472.5ms
60MB
async/await throughput
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
51.6ms
67MB
Deno
32.8ms
64MB
esrun
30ms
36MB
LLRT
687.9ms
11MB
Node.js
58.3ms
51MB
setTimeout churn
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
30.4ms
59MB
Deno
205.5ms
187MB
esrun
54.4ms
57MB
LLRT
47.1ms
42MB
Node.js
40.1ms
84MB
URL parsing
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
72.5ms
86MB
Deno
103.7ms
71MB
esrun
87.3ms
42MB
LLRT
112.3ms
11MB
Node.js
48.7ms
60MB
TextEncoder/TextDecoder (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
21.5ms
59MB
Deno
65.5ms
74MB
esrun
76.9ms
44MB
LLRT
69.3ms
11MB
Node.js
65ms
62MB
TextEncoder/TextDecoder (64 KiB)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
65.1ms
63MB
Deno
226.3ms
63MB
esrun
277.8ms
35MB
LLRT
207.9ms
11MB
Node.js
296ms
51MB
base64 (atob/btoa)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
13.3ms
57MB
Deno
7.4ms
65MB
esrun
22.3ms
34MB
LLRT
32.5ms
11MB
Node.js
6.7ms
51MB
TypedArray / DataView
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
19.7ms
51MB
Deno
12.5ms
64MB
esrun
12.2ms
36MB
LLRT
70.1ms
11MB
Node.js
13.7ms
52MB
Headers / Request parsing
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
261.1ms
87MB
Deno
1504.5ms
148MB
esrun
409.8ms
46MB
LLRT
713ms
11MB
Node.js
425.3ms
71MB
Multipart FormData round trip
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
18.8ms
57MB
Deno
366.9ms
101MB
esrun
83.9ms
41MB
LLRT
1331.2ms
11MB
Node.js
291.2ms
116MB
Date + Intl formatting
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
74.7ms
52MB
Deno
132.2ms
69MB
esrun
131.1ms
40MB
LLRT
Node.js
122.7ms
59MB
ReadableStream piping
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
8.1ms
38MB
Deno
13.7ms
67MB
esrun
10ms
40MB
LLRT
Node.js
21.9ms
57MB
SubtleCrypto SHA-256
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
422.4ms
41MB
Deno
487.5ms
67MB
esrun
327.2ms
32MB
LLRT
324.4ms
11MB
Node.js
503.5ms
55MB
HMAC + AES-GCM
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
77.4ms
37MB
Deno
129ms
66MB
esrun
33.6ms
33MB
LLRT
24.5ms
11MB
Node.js
147.6ms
54MB
ECDSA P-256 sign + verify
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
188.8ms
33MB
Deno
2170.6ms
67MB
esrun
1092.2ms
32MB
LLRT
1012.8ms
11MB
Node.js
306.1ms
55MB
PBKDF2 (10k iterations)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
64.2ms
27MB
Deno
70.4ms
55MB
esrun
96.8ms
25MB
LLRT
97.7ms
11MB
Node.js
71.1ms
45MB
fetch (local server)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
17.5ms
32MB
Deno
32.9ms
63MB
esrun
39.1ms
36MB
LLRT
17.1ms
11MB
Node.js
82.8ms
87MB
File read (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
35.5ms
39MB
Deno
38.1ms
63MB
esrun
38.8ms
39MB
LLRT
26ms
11MB
Node.js
111.2ms
53MB
File read (large)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
23.5ms
89MB
Deno
61.2ms
187MB
esrun
42.4ms
95MB
LLRT
12.5ms
13MB
Node.js
56.5ms
111MB
File write (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
12.2ms
34MB
Deno
84.5ms
62MB
esrun
72.4ms
31MB
LLRT
96.2ms
11MB
Node.js
154.9ms
53MB
File write (large)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
18.9ms
34MB
Deno
40.2ms
101MB
esrun
57.8ms
31MB
LLRT
50.4ms
15MB
Node.js
57.2ms
90MB
File append (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
29.8ms
35MB
Deno
38.7ms
63MB
esrun
30ms
30MB
LLRT
Node.js
100.2ms
54MB
File append (large)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
6.7ms
31MB
Deno
15.7ms
71MB
esrun
18.2ms
26MB
LLRT
Node.js
22.7ms
57MB
File stat (one path)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
49.7ms
35MB
Deno
85.8ms
60MB
esrun
65.3ms
32MB
LLRT
41.5ms
11MB
Node.js
68.9ms
47MB
File stat (1000 paths)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
195.7ms
40MB
Deno
361ms
67MB
esrun
283.6ms
37MB
LLRT
173.8ms
11MB
Node.js
268.4ms
58MB
File exists (one path)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
7.1ms
36MB
Deno
87.9ms
61MB
esrun
51.1ms
31MB
LLRT
48ms
11MB
Node.js
64.8ms
47MB
File exists (1000 paths)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
30.5ms
47MB
Deno
356.1ms
68MB
esrun
224.7ms
32MB
LLRT
195.5ms
11MB
Node.js
253.1ms
58MB
Glob scan
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
28.8ms
47MB
Deno
esrun
49ms
33MB
LLRT
Node.js
182ms
64MB
Spawn a child process
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
95.3ms
47MB
Deno
103.2ms
71MB
esrun
75.6ms
32MB
LLRT
89.4ms
11MB
Node.js
197.1ms
50MB
See full benchmarks →

Why ES-Runtime?

Standard web APIs

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.

Batteries in the binary

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.

ESM everywhere

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.

Written in Rust

The runtime around the engine is safe Rust: no data races, no use-after-free, no buffer overruns to reach for under hostile input.

Powered by V8

The engine behind Chrome and Node.js, embedded from Rust. A baked startup snapshot opens a full realm in about 8 ms.

Capability-gated

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.

Deny by default

A run reaches what the command line named, and nothing else.

RV8 ISOLATEOP BOUNDARY · RUSTTHE HOSTfetch(url)file(path).text()serve(opts, fn)write(path, bytes)env.DATABASE_URLnew Command("sh")netreadlistenwriteenvrunapi.example.com./config.json:8080./out/report.csvDATABASE_URL/bin/shesrun --allow-net --allow-read --allow-listen app.js

Nine capabilities: read, write, imports, net, listen, env, run, signals, workers. The gate is the op, not the import.

Two binaries.

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.

In esdev, not in production

  • TypeScript & JSX
  • CommonJS (converted at build)
  • Bundler
  • Test runner
  • Watch mode
  • Debugger

Not goals at all

  • Node.js compatibility
  • Package installer
  • Linter / formatter
  • FFI
  • Native addons
  • Remote module imports

Ship a runtime you can trust.

Start building

Install both binaries with one command, and run your first module. Standards-based, fast, ESM-only.

Ship it locked down

Nothing is granted unless the command line says so. Build the deploy line that states exactly what your service may touch.