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
SSR_BOUNDARY_WATERFALL fires on the first cold render because of lazy route chunks, and its advice points at data #4105
On the first SSR request after the dev server starts, the root <Loading> boundary reports SSR_BOUNDARY_WATERFALL (3 sequential waits). The waits aren't data reads. They come from fileRoutes() wrapping each code-split route component in lazy(). Each nested route level has to import() its module before the router can render the next level, so the chunks load one after another.
The warning's advice ("derive both from the same inputs", "preload the dependent data or join the requests") sends you looking at queries. The app can't fix this through queries: every query is already preloaded in parallel and wrapped in its own nested <Loading>.
Make the first request a nested route: curl -s -o /dev/null http://localhost:5173/inbox/thr-oncall
Request the same URL again.
Request
Time
Warning
1st (cold)
1.57s
Yes
2nd
0.012s
No
3rd
0.011s
No
[SSR_BOUNDARY_WATERFALL] A <Loading> boundary took 4 render passes — 3 sequential async waits, 173ms end to end: each read could start only after the previous one answered. If a later read doesn't need the earlier answer, derive both from the same inputs so they start together; if the dependency is intrinsic, preload the dependent data or join the requests.
in <Document> › <App> › <Router> › <RouterContextObj> › <Root> › <RootComp> › <Loading>
After you edit a route or component file, the warning comes back once, because Vite invalidates the module and it has to be imported again.
Cause
@solidjs/router/fs → fileRoutes() caches one lazy() component per route src for the lifetime of the process (dist/fs.js, the components Map). On a cold server:
The (mail) layout chunk is imported, and the root boundary suspends.
The layout renders and the router reaches the child, so the page chunk is imported and the boundary suspends again.
One more sequential wait. I didn't pin down which import this is.
After that the lazy components are resolved, render synchronously, and the boundary finishes in one pass.
Expected
One or more of:
Router: on the server, start every matched route's component import together, the same way route preloads already run for every matched level, instead of discovering them one level per render pass.
Diagnostics: recognize waits caused by lazy() module resolution and either skip them or report them separately, with advice about code splitting or eager server imports instead of data reads.
The SSR boundary check now judges each wait by when the awaited work started. A wait counts toward SSR_BOUNDARY_WATERFALL only if something it awaited started after the previous wait landed. lazy() stamps its import with its start time, and the router's query() stamps its fetches. So route chunks and data the router preloads for every matched level no longer count, while chunks nobody preloaded and real data chains still do. When waits are discounted, the finding reports data.parallelWaits, and the skill's guidance now covers chunk waits as well as data.
Activity
fix(solid): judge SSR waterfall waits by when their work started (#4105)
fix(solid): judge SSR waterfall waits by when their work started (#4108)
ryansolid commentedon Oct 16, 2026
Generated by Claude Code