Question presented to candidate:
"In the App Router, a Server Component can be async and await its own data. What does that buy you, and where does it go wrong?"
What a strong answer should cover:
- A Server Component can be
asyncandawaitdirectly in the component body. NouseEffect, no loading state, no race condition — and the fetch runs adjacent to the data source. - Zero client JavaScript for that component, and no data round-tripped through client state.
- The waterfall trap is the real subject: sequential
awaits for independent data serialise round trips that should overlap. - Fixes:
Promise.allfor independent requests; start the promise early and pass it down to be awaited later; hoist fetches out of deeply nested components. - Suspense boundaries make waterfalls survivable — the shell streams immediately and each section arrives as it resolves, so a slow request delays one region rather than the page.
- Request deduplication: React
cache()and the framework's extendedfetchdedupe identical requests within one render pass, which makes colocating fetches safe. - The genuine sequential case: when one request truly depends on the previous result, the waterfall is unavoidable — you make it visible with Suspense instead of pretending it is parallel.
- Client components cannot be
async;use()plus a promise passed from the server is the bridge.
Clarifying questions expected:
- "Are these requests actually independent, or does one need the first result?"
- "Is this Next.js App Router, or another RSC implementation?"
Code / implementation expected: Yes — the sequential-versus-parallel contrast, and passing a promise down to defer the await.