In short
Instead of writing if (loading) checks in every component, Suspense lets you declare one loading screen for a whole section while its code or data gets ready.
A component that lets you 'wait' for something (a lazy component, or async data with newer patterns) and show a fallback UI in the meantime.

Think of it like this
Papad before the main course
The restaurant puts papad on your table while the kitchen finishes your order, so you're not staring at an empty plate. Suspense shows its fallback, your papad, until everything inside is ready, then swaps in the real thing.
Watch it happen
Waiting with a fallback
1/5Page renders a Suspense boundary with a 'Loading posts...' fallback.
The big ideas
What you need to know
fallback is the placeholder
<Suspense fallback={<Spinner />}> shows Spinner while anything inside it is still loading.
Works with code and data
It waits for lazy components, and for data from Suspense-ready tools like use(), TanStack Query's useSuspenseQuery or Next.js.
Nest for finer control
Each Suspense handles only what's inside it, so the header can appear while comments are still loading.
Try skeletons
A grey block shaped like the content stops the layout jumping when the real thing arrives.
See it in code
Walk through the code
1import { Suspense, use } from "react";2 3type Post = { id: number; title: string };4 5function Posts({ postsPromise }: { postsPromise: Promise<Post[]> }) {6 const posts = use(postsPromise); // suspends until resolved7 return <ul>{posts.map((p) => <li key={p.id}>{p.title}</li>)}</ul>;8}9 10export default function Page({ postsPromise }: { postsPromise: Promise<Post[]> }) {11 return (12 <Suspense fallback={<p>Loading posts...</p>}>13 <Posts postsPromise={postsPromise} />14 </Suspense>15 );16}1/3use() reads the promise. If it's still pending, Posts suspends right here.
use() pauses Posts until the promise resolves, and Suspense shows the fallback meanwhile. The promise must be cached or come from a server component, not created on every render.
Save yourself the pain
Common mistakes
Oops
Calling fetch() inside the same component that passes its promise to use().
Do this instead
Every render makes a new promise, so it suspends again and again. Create it once, in a server component or a caching library.
Oops
One Suspense around the whole page, so everything waits for the slowest part.
Do this instead
Wrap slow sections in their own Suspense so the fast parts show up first.
Your mission
Two loading zones
Quick check
One Suspense wraps a Header and a lazy Comments component. Comments is still downloading. What do you see?
Go deeper
- 1Wrap a `React.lazy()` component in `<Suspense fallback={...}>`.
- 2Build a simple loading skeleton as the fallback.
- 3Read how frameworks like Next.js use Suspense for streaming server-rendered UI.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.