| name | nextjs-app-router |
| description | Ensure correct Next.js App Router architecture, rendering strategy, and data fetching. Use whenever working under /app — routing, layouts, server/client component boundaries, data fetching, Suspense, and Server Actions. Defaults to Server Components and adds 'use client' only for interactivity. Not for the Pages Router (/pages). |
Next.js App Router — Skill
Name: nextjs-app-router
Purpose: Ensure correct App Router architecture, rendering strategy, and data fetching in Next.js.
Use this skill whenever working under /app.
Applies when: Routing, layouts, server/client boundaries, data fetching, Suspense, Server Actions.
Do not use when: Working in the Pages Router (/pages) or non-Next.js projects.
Rules
- Server-first: Default to Server Components; add
'use client' only for interactivity or browser APIs.
- Routing/layouts: Use
layout.tsx for shared UI; keep layouts stable; use route groups (group) for organization.
- Data fetching: Fetch in Server Components by default and colocate with usage.
- Rendering strategy: Choose static, cached, or dynamic intentionally; avoid accidental dynamic rendering.
- Client components: Keep them small, prop-driven, and avoid server data fetching inside them.
- Suspense/streaming: Use
<Suspense> for slow or user-specific UI.
- Mutations: Prefer Server Actions and invalidate caches as needed.
- Errors: Use
error.tsx and not-found.tsx for route-level handling.
Workflow
- Decide server vs client boundaries first.
- Choose the rendering strategy (static/cached/dynamic).
- Fetch data in the closest Server Component.
- Isolate interactivity into small Client Components.
- Add Suspense boundaries for dynamic or slow UI.
- Use Server Actions for mutations and add error boundaries.
Checklists
Implementation checklist
Review checklist
Minimal examples
Server Component (default)
export default async function Page() {
const data = await getData();
return <View data={data} />;
}
Client Component (isolated)
"use client";
export function Button({ onClick }: { onClick: () => void }) {
return <button onClick={onClick}>Click</button>;
}
Layout usage
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<Header />
{children}
</>
);
}
Common mistakes / pitfalls
- Marking entire pages as
'use client'
- Fetching server data in Client Components
- Reading request data in shared/cached logic
- Overusing route segment config instead of code-local controls
- Mixing routing concerns with component UI logic