I've been investigating Edge's cold-start performance on the startup-investigation branch and wanted to share findings and get your thoughts on direction before going further.
What I measured
Using hyperfine --warmup 10 --runs 80 on frozen binaries:
| Command |
Edge (current) |
Node.js |
Deno |
Bun |
eval "" |
~41ms |
~40–50ms |
~20–35ms |
~5–12ms |
Edge is already in range with Node. The gap to Deno is real and closeable. Bun is a different engine (JavaScriptCore) so that gap is architectural.
Root cause
The startup path was instrumented with EDGE_STARTUP_TRACE=1 and finer per-bootstrapper timing. The picture is clear:
- ~19ms total is spent executing bootstrap JS on every cold start
- ~8ms of that is
bootstrap/node.js alone
- No V8 startup snapshot exists — V8 parses and compiles all bootstrap JS fresh on every process launch
- Micro-deferral experiments (lazy-loading individual modules) were tried and repeatedly reverted: they shift cost between trace buckets but don't eliminate it
The pre-JS host-side costs (OpenSSL init ~0.7ms, N-API env creation ~1.2ms) are comparatively small. The real leverage is the 19ms of repeated JS compilation.
Two options I'd like your input on
Option A — V8 bytecode cache (lower risk, faster to ship)
Precompile all bootstrap JS to V8 bytecode at build time and embed alongside the source. On startup, V8 deserializes instead of parsing and compiling. Skips the majority of per-module compile overhead.
- Estimated win: ~8–12ms off cold start
- Effort: a few days
- Risk: low — graceful fallback to source if cache is invalid
Option B — V8 startup snapshot (larger win, more involved)
After running all bootstrap JS during a dedicated build step, serialize the V8 heap. Embed the blob in the binary. On startup, deserialize instead of executing any bootstrap JS at all. This is what Node.js and Deno do.
- Estimated win: ~15–18ms off cold start
- Effort: a few weeks
- Risk: medium — requires identifying which bootstrap code is snapshot-safe, build pipeline changes
What's already landed on this branch
Three small wins are already in place:
BuildEffectiveCliState() skips cwd resolution when no --env-file/--experimental-config-file flags are present (~1.7% improvement on -e "")
- Report binding creation deferred to first use
- Native
--help fast path
My ask
@syrusakbary
I'd like to own this area. Before going further I wanted to check:
- Does this direction (closing the startup gap with Deno) align with your priorities?
- Between Option A and B — which scope feels right?
- Any constraints I should be aware of (build pipeline, snapshot safety requirements, platform targets)?
Happy to start with a spike on Option A to get concrete numbers before committing to either approach fully.
I've been investigating Edge's cold-start performance on the
startup-investigationbranch and wanted to share findings and get your thoughts on direction before going further.What I measured
Using
hyperfine --warmup 10 --runs 80on frozen binaries:eval ""Edge is already in range with Node. The gap to Deno is real and closeable. Bun is a different engine (JavaScriptCore) so that gap is architectural.
Root cause
The startup path was instrumented with
EDGE_STARTUP_TRACE=1and finer per-bootstrapper timing. The picture is clear:bootstrap/node.jsaloneThe pre-JS host-side costs (OpenSSL init ~0.7ms, N-API env creation ~1.2ms) are comparatively small. The real leverage is the 19ms of repeated JS compilation.
Two options I'd like your input on
Option A — V8 bytecode cache (lower risk, faster to ship)
Precompile all bootstrap JS to V8 bytecode at build time and embed alongside the source. On startup, V8 deserializes instead of parsing and compiling. Skips the majority of per-module compile overhead.
Option B — V8 startup snapshot (larger win, more involved)
After running all bootstrap JS during a dedicated build step, serialize the V8 heap. Embed the blob in the binary. On startup, deserialize instead of executing any bootstrap JS at all. This is what Node.js and Deno do.
What's already landed on this branch
Three small wins are already in place:
BuildEffectiveCliState()skipscwdresolution when no--env-file/--experimental-config-fileflags are present (~1.7% improvement on-e "")--helpfast pathMy ask
@syrusakbary
I'd like to own this area. Before going further I wanted to check:
Happy to start with a spike on Option A to get concrete numbers before committing to either approach fully.