Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Apply 62 React and Next.js performance optimization rules from Vercel Engineering
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/async-suspense-boundaries.md
1---2title: Strategic Suspense Boundaries3impact: HIGH4impactDescription: faster initial paint5tags: async, suspense, streaming, layout-shift6---78## Strategic Suspense Boundaries910Instead of awaiting data in async components before returning JSX, use Suspense boundaries to show the wrapper UI faster while data loads.1112**Incorrect (wrapper blocked by data fetching):**1314```tsx15async function Page() {16const data = await fetchData() // Blocks entire page1718return (19<div>20<div>Sidebar</div>21<div>Header</div>22<div>23<DataDisplay data={data} />24</div>25<div>Footer</div>26</div>27)28}29```3031The entire layout waits for data even though only the middle section needs it.3233**Correct (wrapper shows immediately, data streams in):**3435```tsx36function Page() {37return (38<div>39<div>Sidebar</div>40<div>Header</div>41<div>42<Suspense fallback={<Skeleton />}>43<DataDisplay />44</Suspense>45</div>46<div>Footer</div>47</div>48)49}5051async function DataDisplay() {52const data = await fetchData() // Only blocks this component53return <div>{data.content}</div>54}55```5657Sidebar, Header, and Footer render immediately. Only DataDisplay waits for data.5859**Alternative (share promise across components):**6061```tsx62function Page() {63// Start fetch immediately, but don't await64const dataPromise = fetchData()6566return (67<div>68<div>Sidebar</div>69<div>Header</div>70<Suspense fallback={<Skeleton />}>71<DataDisplay dataPromise={dataPromise} />72<DataSummary dataPromise={dataPromise} />73</Suspense>74<div>Footer</div>75</div>76)77}7879function DataDisplay({ dataPromise }: { dataPromise: Promise<Data> }) {80const data = use(dataPromise) // Unwraps the promise81return <div>{data.content}</div>82}8384function DataSummary({ dataPromise }: { dataPromise: Promise<Data> }) {85const data = use(dataPromise) // Reuses the same promise86return <div>{data.summary}</div>87}88```8990Both components share the same promise, so only one fetch occurs. Layout renders immediately while both components wait together.9192**When NOT to use this pattern:**9394- Critical data needed for layout decisions (affects positioning)95- SEO-critical content above the fold96- Small, fast queries where suspense overhead isn't worth it97- When you want to avoid layout shift (loading → content jump)9899**Trade-off:** Faster initial paint vs potential layout shift. Choose based on your UX priorities.100