How to fix Cannot use Suspense boundary without an async component in React

ReactINTERMEDIATEMEDIUMUpdated Dec 10, 2025ยท 112 views

React throws this error when a `<Suspense>` boundary never catches a Promise or an async child, so the runtime refuses to render the boundary or its fallback.

Quick fix

Fixes Cannot use Suspense boundary without an async component

  1. Pinpoint the boundary that threw the error
  2. Give the boundary an async child
  3. Use React.lazy or dynamic imports for client-only code
  4. Drop the boundary if the UI no longer suspends
react โ€” error
# Cannot use Suspense boundary without an async component
Cannot use Suspense boundary without an async component

What this error means

A `<Suspense>` boundary only makes sense when one of its descendants can suspend, which happens when a component either throws a `Promise` (such as an `async` server component that `await`s data or a `React.lazy` wrapper) or is streaming data. When the tree stays fully synchronous, React cannot show a fallback and therefore throws this intent-checking error to signal that the boundary is unnecessary or misconfigured. This safeguard was introduced as part of the concurrent/Server Component workflow so that React can reason about when to pause and resume rendering.

Typical symptoms

  • The overlay or console logs the exact message "Cannot use Suspense boundary without an async component" and rendering stops at the Suspense tree.
  • A page that previously rendered now fails to hydrate or compile, usually in a server-first setup like the App Router.
  • The stack trace points to the layout or component that declares `<Suspense>` even though no child is `async` or uses `React.lazy`.
  • No fallback defined inside `<Suspense>` ever appears because React aborts before showing it.
  • React DevTools may highlight the boundary with a warning badge while children stay stuck in the initial render path.

Common causes

  1. You added `<Suspense>` around components that render synchronously and never start a promise (for example, plain JSX without `await`, `use`, or `React.lazy`).
  2. The component that previously fetched data moved outside the boundary, leaving only static markup inside.
  3. A server component declared as `function` instead of `async` after converting to the new App Router/data fetching model.
  4. Client components inside the boundary do not use `React.lazy` or other code-splitting helpers, so they always resolve immediately.
  5. You reused a Suspense boundary from another screen even though the current tree no longer suspends.

How to fix "Cannot use Suspense boundary without an async component"

1Pinpoint the boundary that threw the error

The mistake is almost always right next to the <code>&lt;Suspense&gt;</code> declaration. Look at the file listed in the stack trace and focus on the direct child of the boundary. If the child is a plain component like the one below, nothing inside the boundary suspends and React refuses to let it exist:

<pre><code class="language-tsx">// layout.tsx
import { Suspense } from 'react';

export default function Layout() {
return (
<Suspense fallback={<Loading />}>
<Hero /> // regular, synchronous server component
</Suspense>
);
}
</code></pre>

React throws the error before it tries to render Loading because it sees a Suspense boundary with only synchronous content.

2Give the boundary an async child

Convert the component inside <code>&lt;Suspense&gt;</code> into an <code>async</code> server component that actually suspends by awaiting data or resources. For example:

<pre><code class="language-tsx">// components/Hero.tsx (server)
const Hero = async () => {
const res = await fetch('https://api.example.com/hero', { cache: 'no-store' });
const hero = await res.json();

return <section>{hero.title}</section>;
};

// layout.tsx
<Suspense fallback={<Loading />}>
<Hero />
</Suspense>
</code></pre>

await fetch causes React to suspend, satisfies the boundary, and React now streams the fallback until the promise resolves.

3Use React.lazy or dynamic imports for client-only code

If the boundary wraps a client component, make that component asynchronous with React.lazy so the tree can suspend while the chunk loads:

<pre><code class="language-tsx">const Chart = React.lazy(() => import('./Chart'));

function Dashboard() {
return (
<Suspense fallback={<LoadingChart />}>
<Chart />
</Suspense>
);
}
</code></pre>

The promise that React.lazy returns keeps the boundary honest, and React stops throwing the error.

4Drop the boundary if the UI no longer suspends

If there is no asynchronous work left, the easiest fix is to remove <code>&lt;Suspense&gt;</code> entirely. Keeping an unused boundary only invites this error:

<pre><code class="language-tsx">// remove Suspense when everything is synchronous
export default function Layout() {
return <Hero />; // no boundary needed when Hero renders right away
}
</code></pre>

Only wrap the tree with <code>&lt;Suspense&gt;</code> when you know it suspends (via await, data fetching helpers, or React.lazy).

Advanced notes

Every Suspense boundary must still describe a fallback UI even if it eventually renders instantly. It is safe to add a boundary above a chunk that may or may not suspend as long as at least one descendant actually throws a promise. This is why server architects often place <Suspense> around the portion of the tree that calls await use or await fetch. React validates that requirement early to avoid streaming meaningless fallbacks or confusing builds when using server components.

Frequently asked questions

What does "Cannot use Suspense boundary without an async component" mean?
lazy wrapper) or is streaming data. When the tree stays fully synchronous, React cannot show a fallback and therefore throws this intent-checking error to signal that the boundary is unnecessary or misconfigured. This safeguard was introduced as part of the concurrent/Server Component workflow so that React can reason about when to pause and resume rendering.
How do I fix "Cannot use Suspense boundary without an async component"?
React throws this error when a <Suspense> boundary never catches a Promise or an async child, so the runtime refuses to render the boundary or its fallback.
What causes "Cannot use Suspense boundary without an async component"?
You added <Suspense> around components that render synchronously and never start a promise (for example, plain JSX without await, use, or React.lazy). The component that previously fetched data moved outside the boundary, leaving only static markup inside. A server component declared as function instead of async after converting to the new App Router/data fetching model.
Is the "Cannot use Suspense boundary without an async component" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading