Alpha

A secure, standards-based server runtime.

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

Benchmarks

Cold start (near-empty script)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
4.2ms
12MB
Deno
14.4ms
28MB
esrun
8.4ms
24MB
LLRT
3.6ms
11MB
Node.js
17.1ms
41MB
Parse + run ~100 KB script
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
15.5ms
16MB
Deno
22.4ms
28MB
esrun
3.3ms
11MB
LLRT
10.9ms
14MB
Node.js
34.1ms
46MB
Load a 300-module graph
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
12.6ms
25MB
Deno
32.4ms
32MB
esrun
3.3ms
11MB
LLRT
14.2ms
12MB
Node.js
83.4ms
61MB
Peak resident memory (idle)
Runtime
Perf (lower is better)
Bun
12MB
Deno
28MB
esrun
24MB
LLRT
11MB
Node.js
41MB
Peak resident memory (under load)
Runtime
Perf (lower is better)
Bun
145MB
Deno
123MB
esrun
106MB
LLRT
162MB
Node.js
136MB
Tight compute loop
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
108.2ms
24MB
Deno
233.7ms
39MB
esrun
192.1ms
36MB
LLRT
2002.2ms
11MB
Node.js
193.4ms
54MB
JSON parse/stringify
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
145.4ms
39MB
Deno
192.3ms
56MB
esrun
184.7ms
53MB
LLRT
636.2ms
11MB
Node.js
260.8ms
80MB
JSON (large documents)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
415.4ms
116MB
Deno
514.7ms
138MB
esrun
462.6ms
135MB
LLRT
1622.2ms
143MB
Node.js
667ms
159MB
Regex (match, validate, replace)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
16.5ms
35MB
Deno
62.6ms
40MB
esrun
58.1ms
39MB
LLRT
1168.3ms
11MB
Node.js
64.9ms
56MB
String building and slicing
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
58.7ms
45MB
Deno
57.5ms
48MB
esrun
56.4ms
46MB
LLRT
147.3ms
11MB
Node.js
60.2ms
64MB
structuredClone
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
229.6ms
32MB
Deno
249.8ms
43MB
esrun
267.2ms
51MB
LLRT
310ms
12MB
Node.js
213.1ms
55MB
throw/catch + stack capture
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
308.1ms
48MB
Deno
4120.3ms
63MB
esrun
383.4ms
46MB
LLRT
304.6ms
11MB
Node.js
1410.4ms
64MB
async/await throughput
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
38.3ms
33MB
Deno
30.3ms
40MB
esrun
30.1ms
38MB
LLRT
666.5ms
11MB
Node.js
55.4ms
55MB
setTimeout churn
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
29.5ms
50MB
Deno
236.4ms
167MB
esrun
50.3ms
60MB
LLRT
36.7ms
50MB
Node.js
49.5ms
85MB
URL parsing
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
30.5ms
50MB
Deno
96.3ms
47MB
esrun
84.6ms
46MB
LLRT
109.8ms
11MB
Node.js
33.7ms
63MB
TextEncoder/TextDecoder (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
16.1ms
39MB
Deno
67ms
50MB
esrun
77.8ms
47MB
LLRT
70.4ms
11MB
Node.js
65.8ms
66MB
TextEncoder/TextDecoder (64 KiB)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
72.8ms
41MB
Deno
136.9ms
40MB
esrun
83.6ms
39MB
LLRT
213.1ms
14MB
Node.js
309.6ms
55MB
base64 (atob/btoa)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
11.1ms
38MB
Deno
7.7ms
42MB
esrun
21.7ms
37MB
LLRT
32.8ms
11MB
Node.js
6.9ms
55MB
TypedArray / DataView
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
16.1ms
35MB
Deno
12.7ms
41MB
esrun
12.6ms
39MB
LLRT
72.1ms
12MB
Node.js
13.2ms
56MB
Headers / Request parsing
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
224.4ms
41MB
Deno
1546.3ms
127MB
esrun
410.8ms
50MB
LLRT
726.4ms
12MB
Node.js
429.6ms
76MB
Multipart FormData round trip
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
20ms
47MB
Deno
366.5ms
111MB
esrun
91.9ms
43MB
LLRT
1361.6ms
13MB
Node.js
262.6ms
121MB
Date + Intl formatting
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
75.5ms
42MB
Deno
131.9ms
48MB
esrun
134ms
44MB
LLRT
Node.js
123.5ms
63MB
ReadableStream piping
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
5.7ms
27MB
Deno
10.7ms
43MB
esrun
10.2ms
43MB
LLRT
Node.js
11.1ms
61MB
SubtleCrypto SHA-256
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
423ms
37MB
Deno
417.4ms
42MB
esrun
331.5ms
35MB
LLRT
329.1ms
11MB
Node.js
533.1ms
58MB
HMAC + AES-GCM
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
82.7ms
33MB
Deno
92.1ms
42MB
esrun
33.5ms
36MB
LLRT
24.7ms
11MB
Node.js
213.2ms
63MB
ECDSA P-256 sign + verify
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
190.1ms
25MB
Deno
2209.9ms
41MB
esrun
1120.4ms
35MB
LLRT
1034.3ms
11MB
Node.js
410.6ms
58MB
PBKDF2 (10k iterations)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
63.1ms
18MB
Deno
72ms
34MB
esrun
101.1ms
28MB
LLRT
98.3ms
11MB
Node.js
69.9ms
50MB
fetch (local server)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
17.9ms
22MB
Deno
34.5ms
43MB
esrun
40.5ms
39MB
LLRT
17.7ms
13MB
Node.js
95ms
90MB
File read (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
36.7ms
36MB
Deno
40ms
42MB
esrun
50.6ms
41MB
LLRT
26.7ms
12MB
Node.js
111.9ms
57MB
File read (large)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
16.4ms
37MB
Deno
66.7ms
167MB
esrun
36.7ms
95MB
LLRT
7.1ms
21MB
Node.js
58.7ms
114MB
File write (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
12.3ms
25MB
Deno
87.9ms
42MB
esrun
86.3ms
33MB
LLRT
98.8ms
12MB
Node.js
157.7ms
57MB
File write (large)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
20.7ms
24MB
Deno
40.4ms
81MB
esrun
36.5ms
33MB
LLRT
44ms
20MB
Node.js
59.4ms
93MB
File append (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
32.2ms
26MB
Deno
42.7ms
42MB
esrun
40.2ms
33MB
LLRT
Node.js
95.8ms
57MB
File append (large)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
7.3ms
21MB
Deno
15.8ms
51MB
esrun
9.3ms
27MB
LLRT
Node.js
25.9ms
61MB
File stat (one path)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
47.2ms
27MB
Deno
92.7ms
41MB
esrun
66.8ms
34MB
LLRT
41.7ms
13MB
Node.js
70.5ms
51MB
File stat (1000 paths)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
200ms
36MB
Deno
372.3ms
45MB
esrun
285.9ms
40MB
LLRT
168.7ms
12MB
Node.js
273.8ms
60MB
File exists (one path)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
7.5ms
28MB
Deno
90.2ms
41MB
esrun
52ms
33MB
LLRT
50.2ms
13MB
Node.js
61.2ms
51MB
File exists (1000 paths)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
30.9ms
40MB
Deno
372ms
46MB
esrun
229.2ms
34MB
LLRT
195.5ms
12MB
Node.js
243.5ms
61MB
Glob scan
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
28.1ms
34MB
Deno
esrun
50.5ms
35MB
LLRT
Node.js
190.5ms
67MB
Spawn a child process
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
135.4ms
27MB
Deno
153.9ms
52MB
esrun
88.8ms
35MB
LLRT
129.9ms
12MB
Node.js
255.5ms
55MB
Cold start (near-empty script)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
4.2ms
12MB
Deno
14.4ms
28MB
esrun
8.4ms
24MB
LLRT
3.6ms
11MB
Node.js
17.1ms
41MB
Parse + run ~100 KB script
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
15.5ms
16MB
Deno
22.4ms
28MB
esrun
3.3ms
11MB
LLRT
10.9ms
14MB
Node.js
34.1ms
46MB
Load a 300-module graph
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
12.6ms
25MB
Deno
32.4ms
32MB
esrun
3.3ms
11MB
LLRT
14.2ms
12MB
Node.js
83.4ms
61MB
Peak resident memory (idle)
Runtime
Perf (lower is better)
Bun
12MB
Deno
28MB
esrun
24MB
LLRT
11MB
Node.js
41MB
Peak resident memory (under load)
Runtime
Perf (lower is better)
Bun
145MB
Deno
123MB
esrun
106MB
LLRT
162MB
Node.js
136MB
Tight compute loop
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
108.2ms
24MB
Deno
233.7ms
39MB
esrun
192.1ms
36MB
LLRT
2002.2ms
11MB
Node.js
193.4ms
54MB
JSON parse/stringify
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
145.4ms
39MB
Deno
192.3ms
56MB
esrun
184.7ms
53MB
LLRT
636.2ms
11MB
Node.js
260.8ms
80MB
JSON (large documents)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
415.4ms
116MB
Deno
514.7ms
138MB
esrun
462.6ms
135MB
LLRT
1622.2ms
143MB
Node.js
667ms
159MB
Regex (match, validate, replace)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
16.5ms
35MB
Deno
62.6ms
40MB
esrun
58.1ms
39MB
LLRT
1168.3ms
11MB
Node.js
64.9ms
56MB
String building and slicing
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
58.7ms
45MB
Deno
57.5ms
48MB
esrun
56.4ms
46MB
LLRT
147.3ms
11MB
Node.js
60.2ms
64MB
structuredClone
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
229.6ms
32MB
Deno
249.8ms
43MB
esrun
267.2ms
51MB
LLRT
310ms
12MB
Node.js
213.1ms
55MB
throw/catch + stack capture
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
308.1ms
48MB
Deno
4120.3ms
63MB
esrun
383.4ms
46MB
LLRT
304.6ms
11MB
Node.js
1410.4ms
64MB
async/await throughput
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
38.3ms
33MB
Deno
30.3ms
40MB
esrun
30.1ms
38MB
LLRT
666.5ms
11MB
Node.js
55.4ms
55MB
setTimeout churn
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
29.5ms
50MB
Deno
236.4ms
167MB
esrun
50.3ms
60MB
LLRT
36.7ms
50MB
Node.js
49.5ms
85MB
URL parsing
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
30.5ms
50MB
Deno
96.3ms
47MB
esrun
84.6ms
46MB
LLRT
109.8ms
11MB
Node.js
33.7ms
63MB
TextEncoder/TextDecoder (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
16.1ms
39MB
Deno
67ms
50MB
esrun
77.8ms
47MB
LLRT
70.4ms
11MB
Node.js
65.8ms
66MB
TextEncoder/TextDecoder (64 KiB)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
72.8ms
41MB
Deno
136.9ms
40MB
esrun
83.6ms
39MB
LLRT
213.1ms
14MB
Node.js
309.6ms
55MB
base64 (atob/btoa)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
11.1ms
38MB
Deno
7.7ms
42MB
esrun
21.7ms
37MB
LLRT
32.8ms
11MB
Node.js
6.9ms
55MB
TypedArray / DataView
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
16.1ms
35MB
Deno
12.7ms
41MB
esrun
12.6ms
39MB
LLRT
72.1ms
12MB
Node.js
13.2ms
56MB
Headers / Request parsing
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
224.4ms
41MB
Deno
1546.3ms
127MB
esrun
410.8ms
50MB
LLRT
726.4ms
12MB
Node.js
429.6ms
76MB
Multipart FormData round trip
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
20ms
47MB
Deno
366.5ms
111MB
esrun
91.9ms
43MB
LLRT
1361.6ms
13MB
Node.js
262.6ms
121MB
Date + Intl formatting
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
75.5ms
42MB
Deno
131.9ms
48MB
esrun
134ms
44MB
LLRT
Node.js
123.5ms
63MB
ReadableStream piping
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
5.7ms
27MB
Deno
10.7ms
43MB
esrun
10.2ms
43MB
LLRT
Node.js
11.1ms
61MB
SubtleCrypto SHA-256
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
423ms
37MB
Deno
417.4ms
42MB
esrun
331.5ms
35MB
LLRT
329.1ms
11MB
Node.js
533.1ms
58MB
HMAC + AES-GCM
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
82.7ms
33MB
Deno
92.1ms
42MB
esrun
33.5ms
36MB
LLRT
24.7ms
11MB
Node.js
213.2ms
63MB
ECDSA P-256 sign + verify
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
190.1ms
25MB
Deno
2209.9ms
41MB
esrun
1120.4ms
35MB
LLRT
1034.3ms
11MB
Node.js
410.6ms
58MB
PBKDF2 (10k iterations)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
63.1ms
18MB
Deno
72ms
34MB
esrun
101.1ms
28MB
LLRT
98.3ms
11MB
Node.js
69.9ms
50MB
fetch (local server)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
17.9ms
22MB
Deno
34.5ms
43MB
esrun
40.5ms
39MB
LLRT
17.7ms
13MB
Node.js
95ms
90MB
File read (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
36.7ms
36MB
Deno
40ms
42MB
esrun
50.6ms
41MB
LLRT
26.7ms
12MB
Node.js
111.9ms
57MB
File read (large)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
16.4ms
37MB
Deno
66.7ms
167MB
esrun
36.7ms
95MB
LLRT
7.1ms
21MB
Node.js
58.7ms
114MB
File write (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
12.3ms
25MB
Deno
87.9ms
42MB
esrun
86.3ms
33MB
LLRT
98.8ms
12MB
Node.js
157.7ms
57MB
File write (large)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
20.7ms
24MB
Deno
40.4ms
81MB
esrun
36.5ms
33MB
LLRT
44ms
20MB
Node.js
59.4ms
93MB
File append (small)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
32.2ms
26MB
Deno
42.7ms
42MB
esrun
40.2ms
33MB
LLRT
Node.js
95.8ms
57MB
File append (large)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
7.3ms
21MB
Deno
15.8ms
51MB
esrun
9.3ms
27MB
LLRT
Node.js
25.9ms
61MB
File stat (one path)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
47.2ms
27MB
Deno
92.7ms
41MB
esrun
66.8ms
34MB
LLRT
41.7ms
13MB
Node.js
70.5ms
51MB
File stat (1000 paths)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
200ms
36MB
Deno
372.3ms
45MB
esrun
285.9ms
40MB
LLRT
168.7ms
12MB
Node.js
273.8ms
60MB
File exists (one path)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
7.5ms
28MB
Deno
90.2ms
41MB
esrun
52ms
33MB
LLRT
50.2ms
13MB
Node.js
61.2ms
51MB
File exists (1000 paths)
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
30.9ms
40MB
Deno
372ms
46MB
esrun
229.2ms
34MB
LLRT
195.5ms
12MB
Node.js
243.5ms
61MB
Glob scan
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
28.1ms
34MB
Deno
esrun
50.5ms
35MB
LLRT
Node.js
190.5ms
67MB
Spawn a child process
Runtime
Perf (lower is better)
Memory (lower ↓)
Bun
135.4ms
27MB
Deno
153.9ms
52MB
esrun
88.8ms
35MB
LLRT
129.9ms
12MB
Node.js
255.5ms
55MB
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.

Choosing a runtime? How esrun compares to Node.js, Bun and Deno →

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
Elysia hello-world · Speed & Memory
Runtime
Throughput (higher ↑)
Memory (lower ↓)
Bun
87.8k
47 MB
Deno
82.3k
56 MB
esrun
51.5k
50 MB
Node.js
30.8k
107 MB

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 →

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.