--- name: nextjs-app-router description: Build modern Next.js 13+ applications using App Router architecture with Server Components, Client Components, and advanced routing patterns. Use when implementing server-first rendering, creating nested layouts, building parallel routes, implementing intercepting routes, using React Server Components, optimizing data fetching with server-side async components, implementing streaming with Suspense, managing client-side interactivity boundaries, or leveraging Next.js 13+ app directory features for performant, SEO-friendly React applications. --- # Next.js App Router - Modern React Framework Patterns ## When to use this skill - Building Next.js 13+ applications with App Router - Implementing Server Components for server-first rendering - Creating Client Components for interactive UI elements - Setting up nested layouts that persist across routes - Implementing parallel routes for complex UI patterns - Using intercepting routes for modals and overlays - Optimizing data fetching with async Server Components - Implementing streaming and progressive rendering with Suspense - Managing client/server component boundaries effectively - Building SEO-friendly applications with server-side rendering - Leveraging server actions for form handling - Creating file-based routing with app directory structure ## When to use this skill - Building Next.js 13+ applications with App Router, implementing Server Components, or optimizing React Server Components patterns. - When working on related tasks or features - During development that requires this expertise **Use when**: Building Next.js 13+ applications with App Router, implementing Server Components, or optimizing React Server Components patterns. ## Core Concepts 1. **Server Components by Default** - Components are server-rendered unless marked with 'use client' 2. **File-based Routing** - `/app` directory structure defines routes 3. **Streaming & Suspense** - Progressive rendering for better UX 4. **Data Fetching** - Server-side with automatic caching 5. **Layouts & Templates** - Shared UI that persists across routes ## App Router Structure ``` app/ ├── layout.tsx # Root layout (required) ├── page.tsx # Home page (/) ├── loading.tsx # Loading UI ├── error.tsx # Error UI ├── not-found.tsx # 404 UI ├── dashboard/ │ ├── layout.tsx # Dashboard layout │ ├── page.tsx # /dashboard │ └── settings/ │ └── page.tsx # /dashboard/settings └── api/ └── users/ └── route.ts # API endpoint /api/users ``` ## Server vs Client Components ```typescript // ✅ Server Component (default - no 'use client') // app/page.tsx import { db } from '@/lib/db'; export default async function Page() { // Fetch data on server const users = await db.user.findMany(); return (

Users

{users.map(user => )}
); } // ✅ Client Component (interactive features) // app/components/Counter.tsx 'use client'; import { useState } from 'react'; export function Counter() { const [count, setCount] = useState(0); return ( ); } // ✅ Composition: Server Component with Client Component children // app/page.tsx import { Counter } from './components/Counter'; export default async function Page() { const data = await fetchData(); // Server-side return (

Server Data: {data}

{/* Client interactive component */}
); } ``` ## Data Fetching ```typescript // ✅ Fetch with caching (default: 'force-cache') async function getUsers() { const res = await fetch('https://api.example.com/users', { cache: 'force-cache' // Cached until revalidated }); return res.json(); } // ✅ Revalidate every 60 seconds async function getUsers() { const res = await fetch('https://api.example.com/users', { next: { revalidate: 60 } }); return res.json(); } // ✅ No caching (always fresh) async function getUsers() { const res = await fetch('https://api.example.com/users', { cache: 'no-store' }); return res.json(); } // ✅ Database query (Prisma) import { db } from '@/lib/db'; async function getUser(id: string) { return await db.user.findUnique({ where: { id } }); } ``` ## Dynamic Routes ```typescript // app/posts/[id]/page.tsx interface PageProps { params: { id: string }; searchParams: { [key: string]: string | string[] | undefined }; } export default async function PostPage({ params }: PageProps) { const post = await db.post.findUnique({ where: { id: params.id } }); return
{post.title}
; } // Generate static paths at build time export async function generateStaticParams() { const posts = await db.post.findMany(); return posts.map((post) => ({ id: post.id })); } // Generate metadata export async function generateMetadata({ params }: PageProps) { const post = await db.post.findUnique({ where: { id: params.id } }); return { title: post.title, description: post.excerpt }; } ``` ## Layouts ```typescript // app/layout.tsx (Root Layout - Required) export default function RootLayout({ children }: { children: React.ReactNode; }) { return (
{children}