perf: cache manifest loading and component resolution per route#91599
Open
benfavre wants to merge 1 commit intovercel:canaryfrom
Open
perf: cache manifest loading and component resolution per route#91599benfavre wants to merge 1 commit intovercel:canaryfrom
benfavre wants to merge 1 commit intovercel:canaryfrom
Conversation
In production, manifests and component modules are immutable between deploys. Currently, `loadManifests` in `RouteModule.prepare()` performs 10+ `path.join()` calls and `loadManifestFromRelativePath` invocations per request, and `findPageComponentsImpl` calls `loadComponents` (which loads manifests + resolves modules) on every request. This adds two caches that are only active in production (!isDev): 1. `manifestsCache` on `RouteModule` — caches the entire assembled manifests result object by `srcPage` key, eliminating redundant path construction and manifest lookup overhead. 2. `componentsCache` on `NextNodeServer` — caches `loadComponents` results by `pagePath:isAppPath` key, avoiding repeated manifest loading and module resolution. Both caches are lazily initialized (only allocated when first needed) and are disabled in development mode where manifests change on recompilation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Collaborator
|
Allow CI Workflow Run
Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer |
Contributor
Author
Performance ImpactProfiling setup: Node.js v25.7.0, Before (canary):
After (this PR):
|
Contributor
Author
Performance Impact — UpdatedWith proper build (all PRs compiled), verified via CPU profile:
The manifest cache eliminates 10+ path.join() + Map.get() + function calls per request for the same route. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
loadManifestsresult per route inRouteModule.prepare()— eliminates 10+path.join()+loadManifestFromRelativePathcalls per request in productionloadComponentsresult per page inNextNodeServer.findPageComponentsImpl()— avoids repeated manifest loading and module resolution per request in production!isDev) and lazily initializedBackground
In production, manifests and component modules are immutable between deploys. However,
loadManifestsandloadComponentsare called on every incoming request. While the underlying file reads are already cached byloadManifest/evalManifestinload-manifest.external.ts, the overhead of:path.join()calls to construct manifest pathsloadManifestFromRelativePathloadComponentsdoingrequirePage+ manifest loading per request...adds measurable latency under sustained load.
Changes
packages/next/src/server/route-modules/route-module.tsLoadedManifeststype alias (was inline onloadManifestsreturn)manifestsCache: Map<string, LoadedManifests>(lazily initialized, production-only)loadManifestsresult bysrcPagekey inprepare()packages/next/src/server/next-server.tscomponentsCache: Map<string, LoadComponentsReturnType>(lazily initialized, production-only)loadComponentsresult bypagePath:isAppPathkey infindPageComponentsImpl()Safety
LoadedManifestscontains only manifest data and compiled module references — no per-request stateLoadComponentsReturnTypecontains component modules, manifest data, and static getters — no per-request stateloadManifestfile-level caching is preserved as a lower-level cacheTest plan
isDevis true)🤖 Generated with Claude Code