Next.js App Router Best Practices

Chapter 2 · Practice 4 of 6

Wrap uncached and request-time data in Suspense

From Caching with Cache Components

Why it matters

Some data must be fresh on every request, and that should not hold up the rest of the page. Data like this, and components that read cookies(), headers(), searchParams or dynamic params, should not use 'use cache'.

  1. Wrap them in <Suspense> with a fallback.
  2. The fallback ships in the prerendered static shell.
  3. The real content streams in at request time.

If you skip the boundary, the dev overlay reports a blocking route and points you to the fix.

Example

TSX
export default function Page() {
  return (
    <>
      <Header />
      <Suspense fallback={<CartSkeleton />}>
        <Cart />
      </Suspense>
    </>
  );
}

async function Cart() {
  const session = (await cookies()).get('session')?.value;
  const items = await getCart(session);
  return <CartList items={items} />;
}