The app
directory introduces support for streaming with Suspense for both Node.js and Edge runtimes.
To learn how Streaming works in React and Next.js, it's helpful to understand Server-Side Rendering (SSR) and its limitations.
With SSR, there's a series of steps that need to be completed before a user can see and interact with a page:
These steps are sequential and blocking, meaning the server can only render the HTML for a page once all the data has been fetched. And, on the client, React can only hydrate the UI once the code for all components in the page has been downloaded.
SSR with React and Next.js helps improve the perceived loading performance by showing a non-interactive page to the user as soon as possible.
However, it can still be slow as all data fetching on server needs to be completed before the page can be shown to the user.
Streaming allows you to break down the page's HTML into smaller chunks and progressively send those chunks from the server to the client.
This enables parts of the page to be displayed sooner, without waiting for all the data to load before any UI can be rendered.
Streaming works well with React's component model because each component can be considered a chunk. Components that have higher priority (e.g. product information) or that don't rely on data can be sent first (e.g. layout), and React can start hydration earlier. Components that have lower priority (e.g. reviews, related products) can be sent in the same server request after their data has been fetched.
Streaming is particularly beneficial when you want to prevent long data requests from blocking the page from rendering as it can reduce the Time To First Byte (TTFB) and First Contentful Paint (FCP). It also helps improve Time to Interactive (TTI), especially on slower devices.
You can implement streaming in Next.js using loading.js
(for an entire route segment) or with Suspense boundaries (for more granular control).
Using streaming requires implementing fallback UI that will render while your route is being suspended. This UI should be designed to match the real content that will eventually load.
You can view an example of streaming here.
loading.js
The special file loading.js
allows you to show an instant loading state from the server while the content of a route segment loads. Once all data fetching in the route segment has finished, the loading UI will be swapped for the content.
export default function Loading() {
return <p>Loading...</p>
}
For more granular control, you can wrap your own components in a React Suspense Boundary. <Suspense>
works by wrapping a component that performs an asynchronous action (e.g. fetch data), showing fallback UI (e.g. skeleton, spinner) while it's happening, and then swapping in your component once the action completes.
import { Suspense } from "react";
import { PostFeed, Weather } from "./Components";
export default function Posts() {
return (
<section>
<Suspense fallback={<p>Loading feed...</p>}>
<PostFeed />
</Suspense>
<Suspense fallback={<p>Loading weather...</p>}>
<Weather />
</Suspense>
</section>
);
}
By using Suspense, you get the benefits of:
For more Suspense examples and use cases, please see the React Documentation.
generateMetadata
to complete before streaming UI to the client. This guarantees the first part of a streamed response includes <head>
tags.