React Suspense: start requests before rendering needs them
The React 19 Suspense debate exposed a hidden dependency between rendering and requests. Make data loading explicit and check network behaviour on upgrades.
A framework upgrade can leave every assertion about a page's contents passing while making the page slower to use. The June 2024 React Suspense debate exposed one route to that outcome: independent requests that started together could start in sequence instead. The lasting architectural lesson is to make request initiation explicit, rather than rely on React reaching sibling components in a particular render pass.
That does not require moving every query into one giant parent component. Keep data requirements close to the components that understand them. Give a route, loader or prefetch mechanism responsibility for starting the independent work early enough. Consumption and scheduling are different decisions.
What the June issue actually established
React issue #29898, opened on 14 June 2024, described a change in the React 19 prerelease: after a component suspended, React stopped prerendering its siblings in that attempt. For code that discovered requests only when those siblings rendered, this changed when network work began. The issue contains a contributor's demonstration, not a universal measurement of React applications.
Suspense makes it tempting to read a component tree as a network plan. Put several panels under a boundary, let each read data, and expect the renderer to discover everything. That expectation hides an assumption: the renderer must keep visiting components after encountering something it cannot finish. A scheduling change can disturb the assumption without changing the eventual output.
The June discussion belongs to a release candidate, not a stable React 19 release. Looking back from November 2026, the stable release announcement is dated 5 December 2024. The linked upgrade guide, read in its current form, describes committing the fallback immediately, then scheduling another render to pre-warm suspended siblings. That later behaviour must not be presented as something available in June, or as a promise that every application now avoids waterfalls.
Draw the dependencies before choosing the boundary
Consider an illustrative customer page with account details, recent invoices and support history. Suppose all three requests need only a customer identifier already present in the route. There is no business dependency between them. Making the invoice request wait for account details is an accidental dependency introduced by implementation.
Now change the example. Support history requires a permissions token obtained from the account response. That sequence is genuine. Starting the support request earlier may be impossible or may bypass a necessary authorization step. The useful distinction is between work that is independent and work whose inputs are not yet available.
Write that distinction down before changing JSX. Start the independent requests through the data library or framework's supported loading mechanism. Let each panel consume the corresponding cached result or stable resource. Avoid building a bespoke promise cache simply to make an example look short: request identity, lifetime and error recovery need a real design.
Moving requests into a loader is also insufficient if the loader awaits each independent result before starting the next. The intended property is overlap where dependencies permit it. The folder containing the request does not establish that property.
Make network behaviour part of upgrade acceptance
A sensible upgrade check should answer two questions: does the page still show the right information, and does independent work still begin independently? Those are recommendations for an application's own validation, not tests performed for this article. No React example or performance experiment was executed here.
Choose a business journey that matters, such as opening an account before taking a payment. Compare the current and proposed versions with a cold data cache, then with the cache conditions users normally encounter. Record request start order as well as completion time. A warm cache can hide delayed initiation; an unusually slow server can dominate both runs and obscure the scheduling difference.
Keep the environment comparable. Development behaviour, server rendering, client navigation and a production build need not discover work in identical ways. Test the path users actually take and retain enough information to distinguish a changed dependency graph from ordinary network noise. A screenshot of the final page cannot do that.
Do not turn this into a brittle assertion that every request must start within an arbitrary number of milliseconds. Assert the important relationship where your tooling allows it, and investigate material changes in a representative trace. The business concern is unnecessary waiting on a critical journey, not winning a synthetic timing contest.
Colocation has a legitimate case
The strongest objection is that route-level loading can make components harder to reuse. A parent must know which descendants will appear, optional panels can trigger wasted requests, and a central loader can become a second description of the interface.
Those costs are real. For a rarely opened panel, initiating work only when the user asks may be better than fetching everything on navigation. For a small application with fast cached responses, restructuring the data layer may cost more than the delay it removes. Suspense boundaries also serve presentation goals; they should reflect what users can use independently.
Keep colocation where it helps. Separate the definition of a query from the moment it begins, use the framework's supported preloading facilities, and measure before reorganizing a working application. The conclusion is conditional: remove consequential accidental sequencing, especially when a dependency upgrade exposes it.
For teams planning software maintenance, that is a practical acceptance criterion. An upgrade is complete when the important journey remains correct and its request behaviour is understood. Rendering should consume an intentional data plan, rather than quietly become the only plan the application has.
Paul