---
name: nextjs-app-router-patterns
description: Master Next.js 14+ App Router with Server Components, streaming, parallel routes, and advanced data fetching. Use when building Next.js applications, implementing SSR/SSG, or optimizing React Server Components.
enabled: false
source: github:JuanJoseGonGi/skills
imported-from: github:JuanJoseGonGi/skills
---

# Next.js App Router Patterns

Comprehensive patterns for Next.js 14+ App Router architecture, Server Components, and modern full-stack React development.

## When to Use This Skill

- Building new Next.js applications with App Router
- Migrating from Pages Router to App Router
- Implementing Server Components and streaming
- Setting up parallel and intercepting routes
- Optimizing data fetching and caching
- Building full-stack features with Server Actions

## Core Concepts

### 1. Rendering Modes

| Mode                  | Where        | When to Use                               |
| --------------------- | ------------ | ----------------------------------------- |
| **Server Components** | Server only  | Data fetching, heavy computation, secrets |
| **Client Components** | Browser      | Interactivity, hooks, browser APIs        |
| **Static**            | Build time   | Content that rarely changes               |
| **Dynamic**           | Request time | Personalized or real-time data            |
| **Streaming**         | Progressive  | Large pages, slow data sources            |

### 2. File Conventions

```
app/
├── layout.tsx       # Shared UI wrapper
├── page.tsx         # Route UI
├── loading.tsx      # Loading UI (Suspense)
├── error.tsx        # Error boundary
├── not-found.tsx    # 404 UI
├── route.ts         # API endpoint
├── template.tsx     # Re-mounted layout
├── default.tsx      # Parallel route fallback
└── opengraph-image.tsx  # OG image generation
```

## Quick Start

```typescript
// app/layout.tsx
import { Inter } from 'next/font/google'
import { Providers } from './providers'

const inter = Inter({ subsets: ['latin'] })

export const metadata = {
  title: { default: 'My App', template: '%s | My App' },
  description: 'Built with Next.js App Router',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body className={inter.className}>
        <Providers>{children}</Providers>
      </body>
    </html>
  )
}

// app/page.tsx - Server Component by default
async function getProducts() {
  const res = await fetch('https://api.example.com/products', {
    next: { revalidate: 3600 }, // ISR: revalidate every hour
  })
  return res.json()
}

export default async function HomePage() {
  const products = await getProducts()

  return (
    <main>
      <h1>Products</h1>
      <ProductGrid products={products} />
    </main>
  )
}
```

## Patterns

### Pattern 1: Server Components with Data Fetching

Use `searchParams` (as `Promise`) and `Suspense` boundaries to stream filtered server-fetched data. Colocate `fetch()` with `next.tags` inside the server component that renders the data.

> Full implementation: `references/data-fetching-patterns.md` § Server Components with Data Fetching

### Pattern 2: Client Components with 'use client'

Use `useTransition` + Server Actions for interactive mutations. Keep client components at the leaf level — only mark a component `'use client'` when it needs hooks or browser APIs.

> Full implementation: `references/data-fetching-patterns.md` § Client Components with 'use client'

### Pattern 3: Server Actions

Define in `"use server"` files. Use `cookies()`, `revalidateTag()`, `revalidatePath()`, and `redirect()` for auth checks, cache invalidation, and post-mutation navigation. Return `{ success }` or `{ error }` for client-side feedback.

> Full implementation: `references/data-fetching-patterns.md` § Server Actions

### Pattern 4: Parallel Routes

Use `@slot` directories in the layout to render independent sections (e.g. `@analytics`, `@team`) with their own `loading.tsx` and error boundaries. Layout receives each slot as a named prop.

> Full implementation: `references/routing-and-api-patterns.md` § Parallel Routes

### Pattern 5: Intercepting Routes (Modal Pattern)

Use `(.)` prefix conventions to intercept navigation and show a modal while preserving the full-page route for direct visits and refreshes. Combine with a `@modal` parallel route slot.

> Full implementation: `references/routing-and-api-patterns.md` § Intercepting Routes

### Pattern 6: Streaming with Suspense

Wrap slow async server components in `<Suspense>` with skeleton fallbacks. The page shell renders immediately; slow sections stream in as they resolve.

> Full implementation: `references/data-fetching-patterns.md` § Streaming with Suspense

### Pattern 7: Route Handlers (API Routes)

Export `GET`, `POST`, etc. from `route.ts` files. Use `NextRequest` for search params and body parsing, `NextResponse.json()` for responses. Dynamic segments via `params: Promise<{ id: string }>`.

> Full implementation: `references/routing-and-api-patterns.md` § Route Handlers

### Pattern 8: Metadata and SEO

Export `generateMetadata()` for dynamic meta/OG/Twitter tags. Use `generateStaticParams()` for pre-rendering dynamic segments. Call `notFound()` for missing resources.

> Full implementation: `references/routing-and-api-patterns.md` § Metadata and SEO

## Caching Strategies

```typescript
// No cache (always fresh)
fetch(url, { cache: "no-store" });

// Cache forever (static)
fetch(url, { cache: "force-cache" });

// ISR - revalidate after 60 seconds
fetch(url, { next: { revalidate: 60 } });

// Tag-based invalidation
fetch(url, { next: { tags: ["products"] } });

// Invalidate via Server Action
("use server");
import { revalidateTag, revalidatePath } from "next/cache";

export async function updateProduct(id: string, data: ProductData) {
  await db.product.update({ where: { id }, data });
  revalidateTag("products");
  revalidatePath("/products");
}
```

## Best Practices

### Do's

- **Start with Server Components** - Add 'use client' only when needed
- **Colocate data fetching** - Fetch data where it's used
- **Use Suspense boundaries** - Enable streaming for slow data
- **Leverage parallel routes** - Independent loading states
- **Use Server Actions** - For mutations with progressive enhancement

### Don'ts

- **Don't pass serializable data** - Server → Client boundary limitations
- **Don't use hooks in Server Components** - No useState, useEffect
- **Don't fetch in Client Components** - Use Server Components or React Query
- **Don't over-nest layouts** - Each layout adds to the component tree
- **Don't ignore loading states** - Always provide loading.tsx or Suspense

## Resources

- [Next.js App Router Documentation](https://nextjs.org/docs/app)
- [Server Components RFC](https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md)
- [Vercel Templates](https://vercel.com/templates/next.js)
