react suspense & streaming: a super simple guide - By Sourav Mishra (@souravvmishra)

let's talk about react suspense and streaming in next.js. no jargon, just making your app load fast and feel snappy.

BySourav Mishra4 min read

hey guys, i am sourav mishra. today let's break down react suspense and streaming. it changes how we build fast web apps.

old school server-side rendering (ssr) has a big issue. the user sees a blank screen until the whole page is ready. lol, nobody got time for that.

react suspense fixes this. it lets pieces of your ui "stream" in as soon as they are ready.


why should you even care?

  1. instant feedback: show a loading spinner right away.
  2. faster clicks: parts of the page become clickable faster.
  3. good seo: google can still read your stuff as it streams in.

wait, does this actually work? yes it does, and it's awesome.


the basics: using <Suspense>

it's pretty simple. you just wrap your slow component in a <Suspense> tag.

// components/Dashboard.tsx
import { Suspense } from "react";
import { RevenueChart } from "./RevenueChart";
import { LatestInvoices } from "./LatestInvoices";
import { CardSkeleton } from "./Skeletons";

export default function Dashboard() {
  return (
    <div className="grid gap-6">
      <Suspense fallback={<CardSkeleton />}>
        <RevenueChart />
      </Suspense>
      
      <Suspense fallback={<CardSkeleton />}>
        <LatestInvoices />
      </Suspense>
    </div>
  );
}

in this code, RevenueChart and LatestInvoices fetch data on their own. if the chart takes 2 seconds and invoices take 0.5 seconds, you see invoices first! no waiting for the slow guy.


streaming with loading.tsx

if you use next.js app router, this is already built-in. just add a loading.tsx file to a folder. next.js wraps the page in a suspense boundary for you.

app/
  dashboard/
    layout.tsx
    page.tsx  <-- the slow stuff
    loading.tsx <-- what to show while waiting

loading.tsx:

export default function Loading() {
  return <div className="animate-pulse bg-gray-200 h-96 rounded-lg" />;
}

boom, instant loading states!


fetching data on the server

for streaming to work, fetch your data inside the component that needs it.

// components/RevenueChart.tsx
async function getRevenue() {
  // acting like a slow db
  await new Promise((resolve) => setTimeout(resolve, 3000));
  return "$50,000";
}

export async function RevenueChart() {
  const revenue = await getRevenue();
  
  return (
    <div className="p-6 bg-white shadow rounded">
      <h3 className="text-gray-500">Total Revenue</h3>
      <p className="text-2xl font-bold">{revenue}</p>
    </div>
  );
}

because RevenueChart is an async component, next.js knows what to do. it sends the fallback ui first, then swaps in the real data when it's ready.


best tips and tricks

  • don't wrap everything: keep things separate. wrap independent stuff individually so fast parts load fast.
  • use skeletons: generic spinners are boring. use ui skeletons that look like the real layout.
  • handle errors: always put an <ErrorBoundary> around <Suspense>. if a fetch fails, your whole page won't crash.

wanna see more? read my post on why server actions rule.


wrapping up

streaming is a total game-changer. no more white screen of death. your app feels fast and snappy, even on bad wifi.

if you want to build clean skeleton loaders, check out my tailwind guide.


common questions

q: can i use suspense on the client? yes! it works on the client too. usually for lazy loading or fetching data with things like tanstack query.

q: is this bad for seo? nope. search bots wait for the stream to finish before reading the page.

q: can i put suspense inside suspense? for sure. you can have a big loader for the layout, and tiny loaders for the widgets inside.


written by sourav mishra. just a guy who loves fast react apps.

Share this post

Cover image for react suspense & streaming: a super simple guide

You might also like

See all