React + Next.js Skill
Scope: Next.js/React specifics. Generic web concerns → .claude/skills/web/SKILL.md.
When to use
- Creating or modifying Next.js pages, layouts, or API routes
- Choosing between SSR, SSG, ISR, or CSR for a given route
- Setting up data fetching with Server Components,
getStaticProps, getServerSideProps, or React Query
- Configuring
next.config.js, middleware, or image optimization
- Resolving hydration errors, layout shift, or bundle size regressions
- Integrating auth (NextAuth / Auth.js), i18n, or Edge runtime
Workflow
- Confirm router strategy — ask the owner whether the project uses App Router (
app/) or Pages Router (pages/). Do not mix patterns in the same codebase.
- Classify rendering need per route:
- Purely static content → SSG (
generateStaticParams / getStaticProps)
- Data changes on every request → SSR (Server Component or
getServerSideProps)
- Revalidate on a schedule → ISR (
revalidate option on fetch or revalidate export)
- User-specific, post-login content → CSR inside a Client Component behind a loading boundary
- Scaffold the route:
- App Router: create
app/<segment>/page.tsx + optional layout.tsx, loading.tsx, error.tsx, not-found.tsx
- Pages Router: create
pages/<segment>.tsx, separate _app.tsx / _document.tsx only when necessary
- Data fetching:
- Server Components:
await fetch(url, { next: { revalidate: N } }) directly in the component body
- Client Components:
useSWR or @tanstack/react-query with a thin fetch wrapper; never call a DB directly
- Mutations: use Server Actions (
"use server") for form submissions; avoid round-trip API routes for simple mutations
- State management:
- Local UI state:
useState / useReducer
- Shared ephemeral state: React Context or Zustand (keep stores small and co-located)
- Server-authoritative state: rely on revalidation (
revalidatePath, revalidateTag) rather than client cache invalidation
- Styling:
- Prefer CSS Modules or Tailwind CSS; avoid global style side-effects in component files
- Use
next/font for web fonts to eliminate layout shift
- Images and media: always use
next/image; set explicit width/height or fill + sizes; never use raw <img> for user-facing content
- Bundle audit: run
ANALYZE=true next build (with @next/bundle-analyzer) before merging features that add new dependencies
- Deploy target check: confirm Vercel, Docker (standalone output), or static export (
output: 'export'). Edge runtime has no Node.js APIs — validate before using runtime = 'edge'.
Standards
| Area |
Do |
Do not |
| Components |
Prefer Server Components; add "use client" only when you need browser APIs or hooks |
Mark every component "use client" by default |
| Data fetching |
Co-locate fetch inside the component that needs it |
Prop-drill data through many layers to avoid "extra fetches" |
| Env vars |
Public vars → NEXT_PUBLIC_*; secrets stay server-side only |
Import process.env.SECRET inside a Client Component |
| Dynamic routes |
Use generateStaticParams for known slugs |
Leave high-traffic pages fully dynamic when they could be static |
| Error handling |
Add error.tsx boundaries per segment; log to observability service |
Let unhandled promise rejections crash the route silently |
| Types |
Use TypeScript strict mode; type all params and searchParams |
Use any for Next.js page props |
| Metadata |
Export metadata or generateMetadata from every public page |
Set <title> inside <head> in JSX |
Common mistakes to avoid
- Mixing App Router and Pages Router in the same route segment — they cannot coexist under the same path.
- Calling
cookies() or headers() in a cached Server Component — this opts the component into dynamic rendering silently. Wrap in a dedicated Server Action or route handler.
- Large Client Component boundaries — importing a heavy chart library inside a component that only needs one hook forces the entire library into the client bundle. Split the hook into a tiny Client Component wrapper.
- Missing
key on list items or wrong key (index) — causes React reconciliation bugs; use stable IDs.
- Uncaught waterfall fetches — sequential
await fetch calls in a Server Component that could run in parallel. Use Promise.all.
useRouter().push in Server Components — useRouter is a client hook; use redirect() from next/navigation on the server.
- Forgetting to invalidate cache after mutation — Server Actions must call
revalidatePath() or revalidateTag() or the UI will show stale data.
- Storing secrets in
next.config.js env block — they get bundled into the client. Use .env.local and server-side access only.
Output format
Typical deliverables for a Next.js feature:
app/
<feature>/
page.tsx # Server Component, data fetching at top
layout.tsx # Shared chrome (nav, breadcrumb)
loading.tsx # Suspense fallback UI
error.tsx # Error boundary with reset button
_components/ # Private components (not routable)
FeatureCard.tsx
actions.ts # Server Actions ("use server")
components/ # Shared Client Components
lib/
<feature>.ts # Pure data-access or business logic
Each file should include: TypeScript types for all props and return values, explicit revalidation strategy comment at the top of data-fetching files, and a brief JSDoc on exported functions.
Related checklists
.claude/checklists/security.md
.claude/checklists/performance.md
.claude/checklists/accessibility.md
.claude/checklists/production.md
Related agents
.claude/agents/stack/web/react-next-engineer.md
.claude/agents/engineering/frontend-engineer.md
.claude/agents/engineering/fullstack-engineer.md
.claude/agents/quality/performance-engineer.md
.claude/agents/quality/accessibility-auditor.md
.claude/agents/quality/security-auditor.md
1---2name: react-next3description: Use for React + Next.js apps — App/Pages Router, rendering strategies, data fetching, state, performance, deployment. Triggers — Next.js config, React components, SSR/SSG/ISR decisions.4---56# React + Next.js Skill78**Scope: Next.js/React specifics. Generic web concerns → `.claude/skills/web/SKILL.md`.**910## When to use1112- Creating or modifying Next.js pages, layouts, or API routes13- Choosing between SSR, SSG, ISR, or CSR for a given route14- Setting up data fetching with Server Components, `getStaticProps`, `getServerSideProps`, or React Query15- Configuring `next.config.js`, middleware, or image optimization16- Resolving hydration errors, layout shift, or bundle size regressions17- Integrating auth (NextAuth / Auth.js), i18n, or Edge runtime1819## Workflow20211. **Confirm router strategy** — ask the owner whether the project uses App Router (`app/`) or Pages Router (`pages/`). Do not mix patterns in the same codebase.222. **Classify rendering need per route**:23 - Purely static content → SSG (`generateStaticParams` / `getStaticProps`)24 - Data changes on every request → SSR (Server Component or `getServerSideProps`)25 - Revalidate on a schedule → ISR (`revalidate` option on `fetch` or `revalidate` export)26 - User-specific, post-login content → CSR inside a Client Component behind a loading boundary273. **Scaffold the route**:28 - App Router: create `app/<segment>/page.tsx` + optional `layout.tsx`, `loading.tsx`, `error.tsx`, `not-found.tsx`29 - Pages Router: create `pages/<segment>.tsx`, separate `_app.tsx` / `_document.tsx` only when necessary304. **Data fetching**:31 - Server Components: `await fetch(url, { next: { revalidate: N } })` directly in the component body32 - Client Components: `useSWR` or `@tanstack/react-query` with a thin `fetch` wrapper; never call a DB directly33 - Mutations: use Server Actions (`"use server"`) for form submissions; avoid round-trip API routes for simple mutations345. **State management**:35 - Local UI state: `useState` / `useReducer`36 - Shared ephemeral state: React Context or Zustand (keep stores small and co-located)37 - Server-authoritative state: rely on revalidation (`revalidatePath`, `revalidateTag`) rather than client cache invalidation386. **Styling**:39 - Prefer CSS Modules or Tailwind CSS; avoid global style side-effects in component files40 - Use `next/font` for web fonts to eliminate layout shift417. **Images and media**: always use `next/image`; set explicit `width`/`height` or `fill` + `sizes`; never use raw `<img>` for user-facing content428. **Bundle audit**: run `ANALYZE=true next build` (with `@next/bundle-analyzer`) before merging features that add new dependencies439. **Deploy target check**: confirm Vercel, Docker (standalone output), or static export (`output: 'export'`). Edge runtime has no Node.js APIs — validate before using `runtime = 'edge'`.4445## Standards4647| Area | Do | Do not |48|---|---|---|49| Components | Prefer Server Components; add `"use client"` only when you need browser APIs or hooks | Mark every component `"use client"` by default |50| Data fetching | Co-locate fetch inside the component that needs it | Prop-drill data through many layers to avoid "extra fetches" |51| Env vars | Public vars → `NEXT_PUBLIC_*`; secrets stay server-side only | Import `process.env.SECRET` inside a Client Component |52| Dynamic routes | Use `generateStaticParams` for known slugs | Leave high-traffic pages fully dynamic when they could be static |53| Error handling | Add `error.tsx` boundaries per segment; log to observability service | Let unhandled promise rejections crash the route silently |54| Types | Use TypeScript strict mode; type all `params` and `searchParams` | Use `any` for Next.js page props |55| Metadata | Export `metadata` or `generateMetadata` from every public page | Set `<title>` inside `<head>` in JSX |5657## Common mistakes to avoid5859- **Mixing App Router and Pages Router** in the same route segment — they cannot coexist under the same path.60- **Calling `cookies()` or `headers()` in a cached Server Component** — this opts the component into dynamic rendering silently. Wrap in a dedicated Server Action or route handler.61- **Large Client Component boundaries** — importing a heavy chart library inside a component that only needs one hook forces the entire library into the client bundle. Split the hook into a tiny Client Component wrapper.62- **Missing `key` on list items or wrong key (index)** — causes React reconciliation bugs; use stable IDs.63- **Uncaught waterfall fetches** — sequential `await fetch` calls in a Server Component that could run in parallel. Use `Promise.all`.64- **`useRouter().push` in Server Components** — `useRouter` is a client hook; use `redirect()` from `next/navigation` on the server.65- **Forgetting to invalidate cache after mutation** — Server Actions must call `revalidatePath()` or `revalidateTag()` or the UI will show stale data.66- **Storing secrets in `next.config.js` `env` block** — they get bundled into the client. Use `.env.local` and server-side access only.6768## Output format6970Typical deliverables for a Next.js feature:7172```73app/74 <feature>/75 page.tsx # Server Component, data fetching at top76 layout.tsx # Shared chrome (nav, breadcrumb)77 loading.tsx # Suspense fallback UI78 error.tsx # Error boundary with reset button79 _components/ # Private components (not routable)80 FeatureCard.tsx81 actions.ts # Server Actions ("use server")82components/ # Shared Client Components83lib/84 <feature>.ts # Pure data-access or business logic85```8687Each file should include: TypeScript types for all props and return values, explicit revalidation strategy comment at the top of data-fetching files, and a brief JSDoc on exported functions.8889## Related checklists9091- `.claude/checklists/security.md`92- `.claude/checklists/performance.md`93- `.claude/checklists/accessibility.md`94- `.claude/checklists/production.md`9596## Related agents9798- `.claude/agents/stack/web/react-next-engineer.md`99- `.claude/agents/engineering/frontend-engineer.md`100- `.claude/agents/engineering/fullstack-engineer.md`101- `.claude/agents/quality/performance-engineer.md`102- `.claude/agents/quality/accessibility-auditor.md`103- `.claude/agents/quality/security-auditor.md`