---
name: nextjs-app-router-pro
description: "Full-stack Next.js 14 App Router: server components, actions, streaming, and ISR. Build production Next.js 14 apps end-to-end — App Router layouts, React Server Components, Server Actions, Suspense streaming, and Vercel ISR. Generates route handlers, middleware, and Edge config."
license: MIT
---

# Next.js App Router Pro

A focused skill for building production Next.js 14 applications with the App Router. It scaffolds and wires together the pieces that are easy to get wrong—server vs. client component boundaries, Server Actions, streaming with Suspense, and ISR revalidation—and it writes idiomatic TypeScript that follows the conventions in `app/`. Aimed at developers shipping real apps on Vercel (or any Node/Edge runtime) rather than toy demos.

## When to use it

- You're starting a new App Router project and want correct `layout.tsx` / `page.tsx` / `loading.tsx` / `error.tsx` structure from the first commit.
- You need a mutation flow without hand-rolling an API route—Server Actions with `revalidatePath`/`revalidateTag`.
- A page is slow because one data call blocks the whole render, and you want to stream the rest with `<Suspense>`.
- You're adding `middleware.ts` for auth redirects, locale routing, or rewrites and need the matcher config right.
- You want incremental static regeneration tuned per route instead of rebuilding the world.

## What it does

- **Routing & layouts:** generates nested layouts, route groups `(group)`, dynamic segments `[id]`, catch-alls `[...slug]`, plus `loading`, `error`, and `not-found` boundaries.
- **Server Components by default:** keeps `async`/`await` data fetching on the server and adds `"use client"` only where interactivity actually needs it.
- **Server Actions:** functions marked `"use server"`, called from forms via the `action` prop or `useActionState`, with cache invalidation through `revalidatePath`, `revalidateTag`, and `cookies()`/`headers()` access.
- **Streaming:** wraps slow subtrees in `<Suspense fallback={...}>` and uses `loading.tsx` for route-level streaming.
- **Caching & ISR:** sets `export const revalidate`, `dynamic`, and `fetchCache` segment options, and tags fetches with `next: { tags, revalidate }`.
- **Route Handlers & Edge:** writes `app/api/.../route.ts` (GET/POST exports) and `export const runtime = "edge"` where appropriate.

## Usage

```tsx
// app/posts/actions.ts
"use server";
import { revalidateTag } from "next/cache";

export async function createPost(formData: FormData) {
  await db.post.create({ data: { title: String(formData.get("title")) } });
  revalidateTag("posts");
}

// app/posts/page.tsx
export const revalidate = 60; // ISR
async function Posts() {
  const posts = await fetch(url, { next: { tags: ["posts"] } }).then(r => r.json());
  return posts.map(p => <li key={p.id}>{p.title}</li>);
}
```

## Tips & gotchas

- `revalidatePath`/`revalidateTag` only run on the server—calling them from a client component does nothing. Keep them inside the action.
- A component becomes client-side the moment you use `useState`, `useEffect`, or event handlers; push `"use client"` to the leaf, not the layout, to avoid bloating the bundle.
- `cookies()` and `headers()` opt a route into dynamic rendering—if a route unexpectedly stops being static, check for these calls.
- `middleware.ts` runs on the Edge runtime; Node-only APIs (`fs`, native crypto) won't work there.

## FAQ

**Does it support the Pages Router?** No—this skill is App Router-only (`app/` directory). It targets Next.js 14+ conventions.

**Can Server Actions return data, not just mutate?** Yes. Return a serializable value and read it with `useActionState` (formerly `useFormState`) on the client.

**How do I force a route to always be dynamic?** Add `export const dynamic = "force-dynamic"` to the segment, or use `noStore()` / a dynamic API like `cookies()`.
