Next.js cookbook · Intermediate

Stream slow sections with Suspense

Render the page shell instantly while slow data (recommendations, analytics) loads.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Fetch fast, essential data in the page and wrap slow async Server Components in <Suspense> with skeleton fallbacks so Next.js streams HTML progressively. Use loading.tsx for a route-level fallback. Start independent fetches in parallel to avoid waterfalls.

Solution

// app/products/[id]/page.tsx
import { Suspense } from "react";

export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  const product = await getProduct(id);                      // fast, needed for the shell
  const reviewsPromise = getReviews(id);                     // start early, don't await yet

  return (
    <main>
      <ProductDetails product={product} />
      <Suspense fallback={<ReviewsSkeleton />}>
        <Reviews promise={reviewsPromise} />
      </Suspense>
      <Suspense fallback={<RecommendationsSkeleton />}>
        <Recommendations productId={id} />                    {/* slow service */}
      </Suspense>
    </main>
  );
}

async function Reviews({ promise }: { promise: Promise<Review[]> }) {
  const reviews = await promise;
  return <ReviewList reviews={reviews} />;
}

async function Recommendations({ productId }: { productId: string }) {
  const items = await getRecommendations(productId);         // may take 1–2 s
  return <ProductCarousel items={items} />;
}

Pitfalls

  • Awaiting all data at the top of the page (no streaming).
  • Sequential awaits that could run in parallel.
  • Fallbacks that cause large layout shifts (size skeletons correctly).

Variations

  • loading.tsx per route segment for navigation-level loading UI.
  • Partial Prerendering / Cache Components to serve a static shell with dynamic holes.

Further reading: Next.js: Streaming

Reference: https://nextjs.org/docs/app/getting-started/fetching-data#streaming

More Next.js recipes

Was this page helpful?