You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
workerd schema preload adds about 10 MiB cold heap in client + server bundle #2865
The workerd shims in both @modelcontextprotocol/client@2.0.0 and @modelcontextprotocol/server@2.0.0 call preloadSchemas() at module scope. In a Connecta Worker-example bundle, removing only those two calls for measurement reduced cold used V8 heap by about 10.03 MiB on average across three fresh local workerd isolates per variant.
Pair
Original used heap
Without the two preload calls
1
23,184,168 B
12,485,064 B
2
22,998,196 B
12,478,996 B
3
22,846,584 B
12,503,924 B
Environment: Node 26.9.0, Miniflare 4.20260722.0, workerd 1.20260722.1, compatibility date 2025-01-01, nodejs_compat, both SDK packages 2.0.0.
The script bundles the Worker example, retains its imported export to prevent tree shaking, answers one synthetic request, then reads Runtime.getHeapUsage from the exact core:user: inspector target. The comparison plugin removes the two shim calls without modifying installed dependencies. Each sample uses a fresh Miniflare instance, disposed afterward. No provider is called or Worker deployed.
This measures cold allocation without forced GC, not retained heap after GC or production isolate churn. HeapProfiler.collectGarbage did not respond within ten seconds in this runtime. We have not verified that removing preload preserves all SDK schema paths on Workers and are not shipping a patch or recommending that workaround.
Could the workerd entry avoid eagerly materializing unused schemas while preserving its no-runtime-code-generation requirements? An upstream supported approach would let consumers benefit without modifying their dependencies.
Independent reproduction, plus the cost on the other side of the trade-off.
Setup: Node 26.9.0, Miniflare 4.20260722.0, workerd 1.20260722.1, nodejs_compat, SDK built from main. Five fresh Miniflare instances per variant. Runtime.getHeapUsage is read after one request. "strip" removes only the module-scope preloadSchemas() call from the bundled output.
Bundle
as-is, used heap
strip, used heap
first preloadSchemas() call in strip
empty Worker
0.74 MB
–
–
server
17.0 MB
8.4 MB
12–16 ms
client
17.7 MB
8.9 MB
11–14 ms
server + client
29.6 MB
18.8 MB
11–14 ms
The heap delta reproduces: about 8.6 to 8.8 MB per package here, and about 10.8 MB with both.
Context: the eager call is deliberate. #2483 moved construction back to module scope on workerd, because the lazy construction from #2476 landed on the first billed request of every fresh isolate. The milliseconds above are wall-clock time for the deferred construction in the same isolates, so they are roughly what laziness would put back on the first request. They are not CPU time.
Given that, I see three directions:
Keep the eager call and document the heap cost.
Add an opt-out for memory-constrained Workers.
Build only the era that is actually negotiated.
I can prototype whichever direction maintainers prefer.
Hi maintainers — I’m interested in contributing to this issue. I have experience with production agent platforms and serverless/edge deployments, and I’d like to investigate a narrowly scoped approach for avoiding unnecessary eager schema materialization in the workerd entry points while preserving the no-runtime-code-generation constraint.
Before I start coding, could you confirm which direction you would prefer for this issue: an opt-out for memory-constrained Workers, lazy construction after negotiation, or a focused measurement/documentation change? I’ll keep the work local until there is alignment and will add targeted regression/benchmark coverage.
Activity
furuchanchan commentedon Sep 29, 2026
Independent reproduction, plus the cost on the other side of the trade-off.
Setup: Node 26.9.0, Miniflare 4.20260722.0, workerd 1.20260722.1,
nodejs_compat, SDK built frommain. Five fresh Miniflare instances per variant.Runtime.getHeapUsageis read after one request. "strip" removes only the module-scopepreloadSchemas()call from the bundled output.preloadSchemas()call in stripThe heap delta reproduces: about 8.6 to 8.8 MB per package here, and about 10.8 MB with both.
Context: the eager call is deliberate. #2483 moved construction back to module scope on workerd, because the lazy construction from #2476 landed on the first billed request of every fresh isolate. The milliseconds above are wall-clock time for the deferred construction in the same isolates, so they are roughly what laziness would put back on the first request. They are not CPU time.
Given that, I see three directions:
I can prototype whichever direction maintainers prefer.
prasad-kavuri commentedon Oct 18, 2026
Hi maintainers — I’m interested in contributing to this issue. I have experience with production agent platforms and serverless/edge deployments, and I’d like to investigate a narrowly scoped approach for avoiding unnecessary eager schema materialization in the workerd entry points while preserving the no-runtime-code-generation constraint.
Before I start coding, could you confirm which direction you would prefer for this issue: an opt-out for memory-constrained Workers, lazy construction after negotiation, or a focused measurement/documentation change? I’ll keep the work local until there is alignment and will add targeted regression/benchmark coverage.