Avoid Request Waterfalls in Next.js Server Components
Flags Next.js Server Components, pages, and layouts that await independent requests one at a time instead of starting them in parallel.
What it flags
import { notFound } from 'next/navigation';
import { getDeployments, getMembers, getProject } from '@/lib/data';
import { DeploymentList } from './deployment-list';
import { MemberList } from './member-list';
type Props = { params: Promise<{ projectId: string }> };
export default async function ProjectPage({ params }: Props) {
const { projectId } = await params;
// Each query waits for the previous one, though none depends on another
const project = await getProject(projectId);
const deployments = await getDeployments(projectId);
const members = await getMembers(projectId);
if (!project) notFound();
return (
<main>
<h1>{project.name}</h1>
<DeploymentList deployments={deployments} />
<MemberList members={members} />
</main>
);
}import { notFound } from 'next/navigation';
import { getDeployments, getMembers, getProject } from '@/lib/data';
import { DeploymentList } from './deployment-list';
import { MemberList } from './member-list';
type Props = { params: Promise<{ projectId: string }> };
export default async function ProjectPage({ params }: Props) {
const { projectId } = await params;
const [project, deployments, members] = await Promise.all([
getProject(projectId),
getDeployments(projectId),
getMembers(projectId),
]);
if (!project) notFound();
return (
<main>
<h1>{project.name}</h1>
<DeploymentList deployments={deployments} />
<MemberList members={members} />
</main>
);
}Why it matters
Each await in a Server Component holds the next line until its request finishes, so three independent queries that each take 150 ms cost 450 ms in sequence and about 150 ms in parallel. The same delay builds across components when a parent awaits data before rendering a child that starts its own fetch. The code reads naturally and each query looks fast on its own, so the added latency only shows up in traces or real page timings, and it grows with every call someone appends to the chain.
Agent instructions
cubic checks every pull request against these instructions. Paste them into AGENTS.md or Cursor rules and your AI coding tool follows them while it writes code.
AGENTS.md
Add this section to AGENTS.md at the repository root. Codex, Cursor, and other AI coding tools read it.
## Avoid Request Waterfalls in Next.js Server Components Applies to `**/*.ts`, `**/*.tsx`. Review Next.js Server Components, pages, layouts, generateMetadata, Route Handlers, and data helpers for independent requests that run one after another. Flag changes that: - Await two or more independent calls in sequence (fetch, ORM or SQL queries, SDK calls) when the later call does not use the earlier result; start them together and await Promise.all, or Promise.allSettled when partial failure is acceptable. - Write Promise.all([await a(), await b()]) or await each promise before collecting them, which still runs the calls one at a time. - Await inside a for or for...of loop when iterations do not depend on each other, instead of mapping to promises and awaiting them together or using one batched query. - Make a parent Server Component await data that only a child uses before rendering the child, so the child's own requests start late; let the child fetch its data, or start the request in the parent and pass the unawaited promise down. - Move data needed on first render into a Client Component useEffect when a Server Component could load it, adding a render, hydrate, then fetch round trip on every visit. Do not flag: - Calls that need an earlier result, such as loading a team by user.teamId, or an auth check that must pass before data loads. - Writes that must happen in order, transactions, or loops that deliberately throttle a rate-limited API. - Awaiting params, searchParams, cookies(), or headers() before the data calls. - A layout and its page each awaiting their own data; Next.js renders them in parallel.
Checks files matching **/*.ts, **/*.tsx.
More Next.js agents
See all Next.js code review standards
Run this agent on every pull request
cubic reviews every pull request against the agents you turn on and comments on the lines that break them.