[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6E236PSK26S3ZPTV2NS4FHD":3,"skill-same:01M6E236PSK26S3ZPTV2NS4FHD":74},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":39,"linkOnly":40,"markdownContent":41,"markdownBody":42,"frontMatter":43,"refName":45,"commitSha":46,"skillDirectory":47,"forksCount":48,"repositoryHtmlUrl":49,"repositoryHomepageUrl":50,"ownerHtmlUrl":51,"ownerBlogUrl":52,"ownerDescription":6,"updatedAt":53,"install":54,"resources":67},"01M6E236PSK26S3ZPTV2NS4FHD","nextjs-app-router-fundamentals",null,"Guide for working with Next.js App Router (Next.js 13+). Use when migrating from Pages Router to App Router, creating layouts, implementing routing, handling metadata, or building Next.js 13+ applications. Activates for App Router migration, layout creation, routing patterns, or Next.js 13+ development tasks.","ByeongminLee\u002Fnextjs-claude-code","ByeongminLee","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F71276006?v=4","01M6E1S467E7GC0NE144SWHC0V","Byeongmin Lee","01M6E1S4AV3W0B08Z2YBK26VG9",3,"MIT","https:\u002F\u002Fgithub.com\u002FByeongminLee\u002Fnextjs-claude-code\u002Fblob\u002Fmain\u002Ftemplate\u002Fskills-archive\u002Fnextjs-app-router-fundamentals\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"nextjs app router fundamentals","app","nextjs","router","guide","pages","creation","layout","next","patterns","use","tasks","edit","write","read","Bash","Next.js","applications","routing","development","2026-11-10 10:12:30",false,"---\nname: nextjs-app-router-fundamentals\ndescription: Guide for working with Next.js App Router (Next.js 13+). Use when migrating from Pages Router to App Router, creating layouts, implementing routing, handling metadata, or building Next.js 13+ applications. Activates for App Router migration, layout creation, routing patterns, or Next.js 13+ development tasks.\nallowed-tools: Read, Write, Edit, Glob, Grep, Bash\n---\n\n# Next.js App Router Fundamentals\n\n## Overview\n\nProvide comprehensive guidance for Next.js App Router (Next.js 13+), covering migration from Pages Router, file-based routing conventions, layouts, metadata handling, and modern Next.js patterns.\n\n## TypeScript: NEVER Use `any` Type\n\n**CRITICAL RULE:** This codebase has `@typescript-eslint\u002Fno-explicit-any` enabled. Using `any` will cause build failures.\n\n**❌ WRONG:**\n```typescript\nfunction handleSubmit(e: any) { ... }\nconst data: any[] = [];\n```\n\n**✅ CORRECT:**\n```typescript\nfunction handleSubmit(e: React.FormEvent\u003CHTMLFormElement>) { ... }\nconst data: string[] = [];\n```\n\n### Common Next.js Type Patterns\n\n```typescript\n\u002F\u002F Page props\nfunction Page({ params }: { params: { slug: string } }) { ... }\nfunction Page({ searchParams }: { searchParams: { [key: string]: string | string[] | undefined } }) { ... }\n\n\u002F\u002F Form events\nconst handleSubmit = (e: React.FormEvent\u003CHTMLFormElement>) => { ... }\nconst handleChange = (e: React.ChangeEvent\u003CHTMLInputElement>) => { ... }\n\n\u002F\u002F Server actions\nasync function myAction(formData: FormData) { ... }\n```\n\n## When to Use This Skill\n\nUse this skill when:\n- Migrating from Pages Router (`pages\u002F` directory) to App Router (`app\u002F` directory)\n- Creating Next.js 13+ applications from scratch\n- Working with layouts, templates, and nested routing\n- Implementing metadata and SEO optimizations\n- Building with App Router routing conventions\n- Handling route groups, parallel routes, or intercepting routes basics\n\n## Core Concepts\n\n### App Router vs Pages Router\n\n**Pages Router (Legacy - Next.js 12 and earlier):**\n```\npages\u002F\n├── index.tsx              # Route: \u002F\n├── about.tsx              # Route: \u002Fabout\n├── _app.tsx               # Custom App component\n├── _document.tsx          # Custom Document component\n└── api\u002F                   # API routes\n    └── hello.ts           # API endpoint: \u002Fapi\u002Fhello\n```\n\n**App Router (Modern - Next.js 13+):**\n```\napp\u002F\n├── layout.tsx             # Root layout (required)\n├── page.tsx               # Route: \u002F\n├── about\u002F                 # Route: \u002Fabout\n│   └── page.tsx\n├── blog\u002F\n│   ├── layout.tsx         # Nested layout\n│   └── [slug]\u002F\n│       └── page.tsx       # Dynamic route: \u002Fblog\u002F:slug\n└── api\u002F                   # Route handlers\n    └── hello\u002F\n        └── route.ts       # API endpoint: \u002Fapi\u002Fhello\n```\n\n### File Conventions\n\n**Special Files in App Router:**\n- `layout.tsx` - Shared UI for a segment and its children (preserves state, doesn't re-render)\n- `page.tsx` - Unique UI for a route, makes route publicly accessible\n- `loading.tsx` - Loading UI with React Suspense\n- `error.tsx` - Error UI with Error Boundaries\n- `not-found.tsx` - 404 UI\n- `template.tsx` - Similar to layout but re-renders on navigation\n- `route.ts` - API endpoints (Route Handlers)\n\n**Colocation:**\n- Components, tests, and other files can be colocated in `app\u002F`\n- Only `page.tsx` and `route.ts` files create public routes\n- Other files (components, utils, tests) are NOT routable\n\n## Migration Guide: Pages Router to App Router\n\n### Step 1: Understand the Current Structure\n\nExamine existing Pages Router setup:\n- Read `pages\u002F` directory structure\n- Identify `_app.tsx` - handles global state, layouts, providers\n- Identify `_document.tsx` - customizes HTML structure\n- Note metadata usage (`next\u002Fhead`, `\u003CHead>` component)\n- List all routes and dynamic segments\n\n### Step 2: Create Root Layout\n\nCreate `app\u002Flayout.tsx` - **REQUIRED** for all App Router applications:\n\n```typescript\n\u002F\u002F app\u002Flayout.tsx\nexport const metadata = {\n  title: 'My App',\n  description: 'App description',\n};\n\nexport default function RootLayout({\n  children,\n}: {\n  children: React.ReactNode;\n}) {\n  return (\n    \u003Chtml lang=\"en\">\n      \u003Cbody>{children}\u003C\u002Fbody>\n    \u003C\u002Fhtml>\n  );\n}\n```\n\n**Migration Notes:**\n- Move `_document.tsx` HTML structure to `layout.tsx`\n- Move `_app.tsx` global providers\u002Fwrappers to `layout.tsx`\n- Convert `\u003CHead>` metadata to `metadata` export\n- The root layout **MUST** include `\u003Chtml>` and `\u003Cbody>` tags\n\n### Step 3: Migrate Pages to Routes\n\n**Simple Page Migration:**\n```typescript\n\u002F\u002F Before: pages\u002Findex.tsx\nimport Head from 'next\u002Fhead';\n\nexport default function Home() {\n  return (\n    \u003C>\n      \u003CHead>\n        \u003Ctitle>Home Page\u003C\u002Ftitle>\n      \u003C\u002FHead>\n      \u003Cmain>\n        \u003Ch1>Welcome\u003C\u002Fh1>\n      \u003C\u002Fmain>\n    \u003C\u002F>\n  );\n}\n```\n\n```typescript\n\u002F\u002F After: app\u002Fpage.tsx\nexport default function Home() {\n  return (\n    \u003Cmain>\n      \u003Ch1>Welcome\u003C\u002Fh1>\n    \u003C\u002Fmain>\n  );\n}\n\n\u002F\u002F Metadata moved to layout.tsx or exported here\nexport const metadata = {\n  title: 'Home Page',\n};\n```\n\n**Nested Route Migration:**\n```typescript\n\u002F\u002F Before: pages\u002Fblog\u002F[slug].tsx\nexport default function BlogPost() { ... }\n```\n\n```typescript\n\u002F\u002F After: app\u002Fblog\u002F[slug]\u002Fpage.tsx\nexport default function BlogPost() { ... }\n```\n\n### Step 4: Update Navigation\n\nReplace anchor tags with Next.js Link:\n\n```typescript\n\u002F\u002F Before (incorrect in App Router)\n\u003Ca href=\"\u002Fabout\">About\u003C\u002Fa>\n\n\u002F\u002F After (correct)\nimport Link from 'next\u002Flink';\n\u003CLink href=\"\u002Fabout\">About\u003C\u002FLink>\n```\n\n### Step 5: Clean Up Pages Directory\n\nAfter migration:\n- Remove all page files from `pages\u002F` directory\n- Keep `pages\u002Fapi\u002F` if you're not migrating API routes yet\n- Remove `_app.tsx` and `_document.tsx` (functionality moved to layout)\n- Optionally delete empty `pages\u002F` directory\n\n## Metadata Handling\n\n### Static Metadata\n\n```typescript\n\u002F\u002F app\u002Fpage.tsx or app\u002Flayout.tsx\nimport type { Metadata } from 'next';\n\nexport const metadata: Metadata = {\n  title: 'My Page',\n  description: 'Page description',\n  keywords: ['nextjs', 'react'],\n  openGraph: {\n    title: 'My Page',\n    description: 'Page description',\n    images: ['\u002Fog-image.jpg'],\n  },\n};\n```\n\n### Dynamic Metadata\n\n```typescript\n\u002F\u002F app\u002Fblog\u002F[slug]\u002Fpage.tsx\nexport async function generateMetadata({\n  params\n}: {\n  params: { slug: string }\n}): Promise\u003CMetadata> {\n  const post = await getPost(params.slug);\n\n  return {\n    title: post.title,\n    description: post.excerpt,\n  };\n}\n```\n\n## Layouts and Nesting\n\n### Creating Nested Layouts\n\n```typescript\n\u002F\u002F app\u002Flayout.tsx - Root layout\nexport default function RootLayout({ children }) {\n  return (\n    \u003Chtml>\n      \u003Cbody>\n        \u003CHeader \u002F>\n        {children}\n        \u003CFooter \u002F>\n      \u003C\u002Fbody>\n    \u003C\u002Fhtml>\n  );\n}\n\n\u002F\u002F app\u002Fblog\u002Flayout.tsx - Blog layout\nexport default function BlogLayout({ children }) {\n  return (\n    \u003Cdiv>\n      \u003CBlogSidebar \u002F>\n      \u003Cmain>{children}\u003C\u002Fmain>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n**Layout Behavior:**\n- Layouts preserve state across navigation\n- Layouts don't re-render on route changes\n- Parent layouts wrap child layouts\n- Root layout is required and wraps entire app\n\n## Routing Patterns\n\n### Dynamic Routes\n\n```typescript\n\u002F\u002F app\u002Fblog\u002F[slug]\u002Fpage.tsx\nexport default function BlogPost({\n  params\n}: {\n  params: { slug: string }\n}) {\n  return \u003Carticle>Post: {params.slug}\u003C\u002Farticle>;\n}\n```\n\n### Catch-All Routes\n\n```typescript\n\u002F\u002F app\u002Fshop\u002F[...slug]\u002Fpage.tsx - Matches \u002Fshop\u002Fa, \u002Fshop\u002Fa\u002Fb, etc.\nexport default function Shop({\n  params\n}: {\n  params: { slug: string[] }\n}) {\n  return \u003Cdiv>Path: {params.slug.join('\u002F')}\u003C\u002Fdiv>;\n}\n```\n\n### Optional Catch-All\n\n```typescript\n\u002F\u002F app\u002Fshop\u002F[[...slug]]\u002Fpage.tsx - Matches \u002Fshop AND \u002Fshop\u002Fa, \u002Fshop\u002Fa\u002Fb\n```\n\n### Route Groups\n\nGroup routes without affecting URL:\n\n```\napp\u002F\n├── (marketing)\u002F\n│   ├── about\u002F\n│   │   └── page.tsx      # \u002Fabout\n│   └── contact\u002F\n│       └── page.tsx      # \u002Fcontact\n└── (shop)\u002F\n    └── products\u002F\n        └── page.tsx      # \u002Fproducts\n```\n\n## Common Migration Pitfalls\n\n### Pitfall 1: Forgetting Root Layout HTML Tags\n\n**Wrong:**\n```typescript\nexport default function RootLayout({ children }) {\n  return \u003Cdiv>{children}\u003C\u002Fdiv>; \u002F\u002F Missing \u003Chtml> and \u003Cbody>\n}\n```\n\n**Correct:**\n```typescript\nexport default function RootLayout({ children }) {\n  return (\n    \u003Chtml lang=\"en\">\n      \u003Cbody>{children}\u003C\u002Fbody>\n    \u003C\u002Fhtml>\n  );\n}\n```\n\n### Pitfall 2: Using `next\u002Fhead` in App Router\n\n**Wrong:**\n```typescript\nimport Head from 'next\u002Fhead';\n\nexport default function Page() {\n  return (\n    \u003C>\n      \u003CHead>\u003Ctitle>Title\u003C\u002Ftitle>\u003C\u002FHead>\n      \u003Cmain>Content\u003C\u002Fmain>\n    \u003C\u002F>\n  );\n}\n```\n\n**Correct:**\n```typescript\nexport const metadata = { title: 'Title' };\n\nexport default function Page() {\n  return \u003Cmain>Content\u003C\u002Fmain>;\n}\n```\n\n### Pitfall 3: Not Removing Pages Directory\n\nAfter migrating routes, remove the old `pages\u002F` directory files to avoid confusion. The build will fail if you have conflicting routes.\n\n### Pitfall 4: Missing `page.tsx` Files\n\nRoutes are NOT accessible without a `page.tsx` file. Layouts alone don't create routes.\n\n```\napp\u002F\n├── blog\u002F\n│   ├── layout.tsx   # NOT a route\n│   └── page.tsx     # This makes \u002Fblog accessible\n```\n\n### Pitfall 5: Incorrect Link Usage\n\n**Wrong:**\n```typescript\n\u003Ca href=\"\u002Fabout\">About\u003C\u002Fa>  \u002F\u002F Works but causes full page reload\n```\n\n**Correct:**\n```typescript\nimport Link from 'next\u002Flink';\n\u003CLink href=\"\u002Fabout\">About\u003C\u002FLink>  \u002F\u002F Client-side navigation\n```\n\n## Server Components vs Client Components\n\n### Default: Server Components\n\nAll components in `app\u002F` are Server Components by default:\n\n```typescript\n\u002F\u002F app\u002Fpage.tsx - Server Component (default)\nexport default async function Page() {\n  const data = await fetch('https:\u002F\u002Fapi.example.com\u002Fdata');\n  const json = await data.json();\n\n  return \u003Cdiv>{json.title}\u003C\u002Fdiv>;\n}\n```\n\n**Benefits:**\n- Can use async\u002Fawait directly\n- Direct database\u002FAPI access\n- Zero client-side JavaScript\n- Automatic code splitting\n\n### Client Components\n\nUse `'use client'` directive when you need:\n- Interactive elements (onClick, onChange, etc.)\n- React hooks (useState, useEffect, useContext, etc.)\n- Browser APIs (window, localStorage, etc.)\n- Event listeners\n\n```typescript\n\u002F\u002F app\u002Fcomponents\u002FCounter.tsx\n'use client';\n\nimport { useState } from 'react';\n\nexport default function Counter() {\n  const [count, setCount] = useState(0);\n\n  return (\n    \u003Cbutton onClick={() => setCount(count + 1)}>\n      Count: {count}\n    \u003C\u002Fbutton>\n  );\n}\n```\n\n## Data Fetching Patterns\n\n### Server Component Data Fetching\n\n```typescript\n\u002F\u002F app\u002Fposts\u002Fpage.tsx\nasync function getPosts() {\n  const res = await fetch('https:\u002F\u002Fapi.example.com\u002Fposts', {\n    next: { revalidate: 3600 } \u002F\u002F Revalidate every hour\n  });\n  return res.json();\n}\n\nexport default async function PostsPage() {\n  const posts = await getPosts();\n\n  return (\n    \u003Cul>\n      {posts.map(post => (\n        \u003Cli key={post.id}>{post.title}\u003C\u002Fli>\n      ))}\n    \u003C\u002Ful>\n  );\n}\n```\n\n### Parallel Data Fetching\n\n```typescript\nexport default async function Page() {\n  \u002F\u002F Fetch in parallel\n  const [posts, users] = await Promise.all([\n    fetch('https:\u002F\u002Fapi.example.com\u002Fposts').then(r => r.json()),\n    fetch('https:\u002F\u002Fapi.example.com\u002Fusers').then(r => r.json()),\n  ]);\n\n  return (\u002F* render *\u002F);\n}\n```\n\n## Static Site Generation with generateStaticParams\n\n### Overview\n\n`generateStaticParams` is the App Router equivalent of `getStaticPaths` from the Pages Router. It generates static pages at build time for dynamic routes.\n\n### Basic Usage\n\n```typescript\n\u002F\u002F app\u002Fblog\u002F[id]\u002Fpage.tsx\nexport async function generateStaticParams() {\n  \u002F\u002F Return array of params to pre-render\n  return [\n    { id: '1' },\n    { id: '2' },\n    { id: '3' },\n  ];\n}\n\nexport default function BlogPost({\n  params\n}: {\n  params: { id: string }\n}) {\n  return \u003Carticle>Blog post {params.id}\u003C\u002Farticle>;\n}\n```\n\n**Key Points:**\n- Returns an array of objects with route parameter keys\n- Each object represents one page to pre-render at build time\n- Function must be exported and named `generateStaticParams`\n- Works ONLY in Server Components (no `'use client'` directive)\n- Replaces Pages Router's `getStaticPaths`\n\n### Fetching Data for Static Params\n\n```typescript\n\u002F\u002F app\u002Fblog\u002F[slug]\u002Fpage.tsx\nexport async function generateStaticParams() {\n  const posts = await fetch('https:\u002F\u002Fapi.example.com\u002Fposts').then(r => r.json());\n\n  return posts.map((post: { slug: string }) => ({\n    slug: post.slug,\n  }));\n}\n\nexport default async function BlogPost({\n  params\n}: {\n  params: { slug: string }\n}) {\n  const post = await fetch(`https:\u002F\u002Fapi.example.com\u002Fposts\u002F${params.slug}`).then(r => r.json());\n\n  return (\n    \u003Carticle>\n      \u003Ch1>{post.title}\u003C\u002Fh1>\n      \u003Cp>{post.content}\u003C\u002Fp>\n    \u003C\u002Farticle>\n  );\n}\n```\n\n### Multiple Dynamic Segments\n\n```typescript\n\u002F\u002F app\u002Fproducts\u002F[category]\u002F[id]\u002Fpage.tsx\nexport async function generateStaticParams() {\n  const categories = await getCategories();\n\n  const params = [];\n  for (const category of categories) {\n    const products = await getProducts(category.slug);\n    for (const product of products) {\n      params.push({\n        category: category.slug,\n        id: product.id,\n      });\n    }\n  }\n\n  return params;\n}\n\nexport default function ProductPage({\n  params\n}: {\n  params: { category: string; id: string }\n}) {\n  return \u003Cdiv>Category: {params.category}, Product: {params.id}\u003C\u002Fdiv>;\n}\n```\n\n### Dynamic Behavior Configuration\n\n```typescript\n\u002F\u002F app\u002Fblog\u002F[id]\u002Fpage.tsx\nexport async function generateStaticParams() {\n  return [{ id: '1' }, { id: '2' }];\n}\n\n\u002F\u002F Control behavior for non-pre-rendered paths\nexport const dynamicParams = true; \u002F\u002F default - allows runtime generation\n\u002F\u002F export const dynamicParams = false; \u002F\u002F returns 404 for non-pre-rendered paths\n\nexport default function BlogPost({\n  params\n}: {\n  params: { id: string }\n}) {\n  return \u003Carticle>Post {params.id}\u003C\u002Farticle>;\n}\n```\n\n**Options:**\n- `dynamicParams = true` (default): Non-pre-rendered paths generated on-demand\n- `dynamicParams = false`: Non-pre-rendered paths return 404\n\n### Common Patterns\n\n**Pattern 1: Simple ID-based routes**\n```typescript\nexport async function generateStaticParams() {\n  return [\n    { id: '1' },\n    { id: '2' },\n    { id: '3' },\n  ];\n}\n```\n\n**Pattern 2: Fetch from API**\n```typescript\nexport async function generateStaticParams() {\n  const items = await fetch('https:\u002F\u002Fapi.example.com\u002Fitems').then(r => r.json());\n  return items.map(item => ({ id: item.id }));\n}\n```\n\n**Pattern 3: Database query**\n```typescript\nexport async function generateStaticParams() {\n  const posts = await db.post.findMany();\n  return posts.map(post => ({ slug: post.slug }));\n}\n```\n\n### Migration from Pages Router\n\n**Before (Pages Router):**\n```typescript\n\u002F\u002F pages\u002Fblog\u002F[id].tsx\nexport async function getStaticPaths() {\n  return {\n    paths: [\n      { params: { id: '1' } },\n      { params: { id: '2' } },\n    ],\n    fallback: false,\n  };\n}\n\nexport async function getStaticProps({ params }) {\n  return { props: { id: params.id } };\n}\n```\n\n**After (App Router):**\n```typescript\n\u002F\u002F app\u002Fblog\u002F[id]\u002Fpage.tsx\nexport async function generateStaticParams() {\n  return [\n    { id: '1' },\n    { id: '2' },\n  ];\n}\n\nexport const dynamicParams = false; \u002F\u002F equivalent to fallback: false\n\nexport default function BlogPost({ params }: { params: { id: string } }) {\n  return \u003Cdiv>Post {params.id}\u003C\u002Fdiv>;\n}\n```\n\n### Common Mistakes to Avoid\n\n**❌ Wrong: Using `'use client'`**\n```typescript\n'use client'; \u002F\u002F ERROR! generateStaticParams only works in Server Components\n\nexport async function generateStaticParams() {\n  return [{ id: '1' }];\n}\n```\n\n**❌ Wrong: Using Pages Router pattern**\n```typescript\nexport async function getStaticPaths() { \u002F\u002F Wrong API!\n  return { paths: [...], fallback: false };\n}\n```\n\n**❌ Wrong: Missing export keyword**\n```typescript\nasync function generateStaticParams() { \u002F\u002F Must be exported!\n  return [{ id: '1' }];\n}\n```\n\n**✅ Correct: Clean Server Component**\n```typescript\n\u002F\u002F app\u002Fblog\u002F[id]\u002Fpage.tsx\n\u002F\u002F No 'use client' directive\n\nexport async function generateStaticParams() {\n  return [{ id: '1' }, { id: '2' }];\n}\n\nexport default function Page({ params }: { params: { id: string } }) {\n  return \u003Cdiv>Post {params.id}\u003C\u002Fdiv>;\n}\n```\n\n**CRITICAL IMPLEMENTATION NOTE:**\n\nWhen asked to \"write\" or \"implement\" `generateStaticParams`:\n- **DO** use the Edit or Write tool to modify the actual file\n- **DO** add the function to the existing page.tsx file\n- **DO** remove any TODO comments about generateStaticParams\n- **DON'T** just output code in markdown - actually implement it\n- **DON'T** show code without writing it to the file\n\n## Testing and Validation\n\nWhen migrating or building with App Router, verify:\n\n1. **Structure:**\n   - `app\u002F` directory exists\n   - Root `layout.tsx` exists with `\u003Chtml>` and `\u003Cbody>`\n   - Each route has a `page.tsx` file\n\n2. **Metadata:**\n   - No `next\u002Fhead` imports in App Router\n   - Metadata exported from pages or layouts\n   - Metadata properly typed with `Metadata` type\n\n3. **Navigation:**\n   - Using `Link` component from `next\u002Flink`\n   - Not using plain `\u003Ca>` tags for internal navigation\n\n4. **Cleanup:**\n   - No remaining page files in `pages\u002F` directory\n   - `_app.tsx` and `_document.tsx` removed\n   - Old metadata patterns removed\n\n## Quick Reference\n\n### File Structure Mapping\n\n| Pages Router | App Router | Purpose |\n|-------------|-----------|---------|\n| `pages\u002Findex.tsx` | `app\u002Fpage.tsx` | Home route |\n| `pages\u002Fabout.tsx` | `app\u002Fabout\u002Fpage.tsx` | About route |\n| `pages\u002F[id].tsx` | `app\u002F[id]\u002Fpage.tsx` | Dynamic route |\n| `pages\u002F_app.tsx` | `app\u002Flayout.tsx` | Global layout |\n| `pages\u002F_document.tsx` | `app\u002Flayout.tsx` | HTML structure |\n| `pages\u002Fapi\u002Fhello.ts` | `app\u002Fapi\u002Fhello\u002Froute.ts` | API route |\n\n### Common Commands\n\n```bash\n# Create new Next.js app with App Router\nnpx create-next-app@latest my-app\n\n# Run development server\nnpm run dev\n\n# Build for production\nnpm run build\n\n# Start production server\nnpm start\n```\n\n## Additional Resources\n\nFor more advanced routing patterns (parallel routes, intercepting routes, route handlers), refer to the `nextjs-advanced-routing` skill.\n\nFor Server vs Client component best practices and anti-patterns, refer to the `nextjs-server-client-components` and `nextjs-anti-patterns` skills.\n","# Next.js App Router Fundamentals\n\n## Overview\n\nProvide comprehensive guidance for Next.js App Router (Next.js 13+), covering migration from Pages Router, file-based routing conventions, layouts, metadata handling, and modern Next.js patterns.\n\n## TypeScript: NEVER Use `any` Type\n\n**CRITICAL RULE:** This codebase has `@typescript-eslint\u002Fno-explicit-any` enabled. Using `any` will cause build failures.\n\n**❌ WRONG:**\n```typescript\nfunction handleSubmit(e: any) { ... }\nconst data: any[] = [];\n```\n\n**✅ CORRECT:**\n```typescript\nfunction handleSubmit(e: React.FormEvent\u003CHTMLFormElement>) { ... }\nconst data: string[] = [];\n```\n\n### Common Next.js Type Patterns\n\n```typescript\n\u002F\u002F Page props\nfunction Page({ params }: { params: { slug: string } }) { ... }\nfunction Page({ searchParams }: { searchParams: { [key: string]: string | string[] | undefined } }) { ... }\n\n\u002F\u002F Form events\nconst handleSubmit = (e: React.FormEvent\u003CHTMLFormElement>) => { ... }\nconst handleChange = (e: React.ChangeEvent\u003CHTMLInputElement>) => { ... }\n\n\u002F\u002F Server actions\nasync function myAction(formData: FormData) { ... }\n```\n\n## When to Use This Skill\n\nUse this skill when:\n- Migrating from Pages Router (`pages\u002F` directory) to App Router (`app\u002F` directory)\n- Creating Next.js 13+ applications from scratch\n- Working with layouts, templates, and nested routing\n- Implementing metadata and SEO optimizations\n- Building with App Router routing conventions\n- Handling route groups, parallel routes, or intercepting routes basics\n\n## Core Concepts\n\n### App Router vs Pages Router\n\n**Pages Router (Legacy - Next.js 12 and earlier):**\n```\npages\u002F\n├── index.tsx              # Route: \u002F\n├── about.tsx              # Route: \u002Fabout\n├── _app.tsx               # Custom App component\n├── _document.tsx          # Custom Document component\n└── api\u002F                   # API routes\n    └── hello.ts           # API endpoint: \u002Fapi\u002Fhello\n```\n\n**App Router (Modern - Next.js 13+):**\n```\napp\u002F\n├── layout.tsx             # Root layout (required)\n├── page.tsx               # Route: \u002F\n├── about\u002F                 # Route: \u002Fabout\n│   └── page.tsx\n├── blog\u002F\n│   ├── layout.tsx         # Nested layout\n│   └── [slug]\u002F\n│       └── page.tsx       # Dynamic route: \u002Fblog\u002F:slug\n└── api\u002F                   # Route handlers\n    └── hello\u002F\n        └── route.ts       # API endpoint: \u002Fapi\u002Fhello\n```\n\n### File Conventions\n\n**Special Files in App Router:**\n- `layout.tsx` - Shared UI for a segment and its children (preserves state, doesn't re-render)\n- `page.tsx` - Unique UI for a route, makes route publicly accessible\n- `loading.tsx` - Loading UI with React Suspense\n- `error.tsx` - Error UI with Error Boundaries\n- `not-found.tsx` - 404 UI\n- `template.tsx` - Similar to layout but re-renders on navigation\n- `route.ts` - API endpoints (Route Handlers)\n\n**Colocation:**\n- Components, tests, and other files can be colocated in `app\u002F`\n- Only `page.tsx` and `route.ts` files create public routes\n- Other files (components, utils, tests) are NOT routable\n\n## Migration Guide: Pages Router to App Router\n\n### Step 1: Understand the Current Structure\n\nExamine existing Pages Router setup:\n- Read `pages\u002F` directory structure\n- Identify `_app.tsx` - handles global state, layouts, providers\n- Identify `_document.tsx` - customizes HTML structure\n- Note metadata usage (`next\u002Fhead`, `\u003CHead>` component)\n- List all routes and dynamic segments\n\n### Step 2: Create Root Layout\n\nCreate `app\u002Flayout.tsx` - **REQUIRED** for all App Router applications:\n\n```typescript\n\u002F\u002F app\u002Flayout.tsx\nexport const metadata = {\n  title: 'My App',\n  description: 'App description',\n};\n\nexport default function RootLayout({\n  children,\n}: {\n  children: React.ReactNode;\n}) {\n  return (\n    \u003Chtml lang=\"en\">\n      \u003Cbody>{children}\u003C\u002Fbody>\n    \u003C\u002Fhtml>\n  );\n}\n```\n\n**Migration Notes:**\n- Move `_document.tsx` HTML structure to `layout.tsx`\n- Move `_app.tsx` global providers\u002Fwrappers to `layout.tsx`\n- Convert `\u003CHead>` metadata to `metadata` export\n- The root layout **MUST** include `\u003Chtml>` and `\u003Cbody>` tags\n\n### Step 3: Migrate Pages to Routes\n\n**Simple Page Migration:**\n```typescript\n\u002F\u002F Before: pages\u002Findex.tsx\nimport Head from 'next\u002Fhead';\n\nexport default function Home() {\n  return (\n    \u003C>\n      \u003CHead>\n        \u003Ctitle>Home Page\u003C\u002Ftitle>\n      \u003C\u002FHead>\n      \u003Cmain>\n        \u003Ch1>Welcome\u003C\u002Fh1>\n      \u003C\u002Fmain>\n    \u003C\u002F>\n  );\n}\n```\n\n```typescript\n\u002F\u002F After: app\u002Fpage.tsx\nexport default function Home() {\n  return (\n    \u003Cmain>\n      \u003Ch1>Welcome\u003C\u002Fh1>\n    \u003C\u002Fmain>\n  );\n}\n\n\u002F\u002F Metadata moved to layout.tsx or exported here\nexport const metadata = {\n  title: 'Home Page',\n};\n```\n\n**Nested Route Migration:**\n```typescript\n\u002F\u002F Before: pages\u002Fblog\u002F[slug].tsx\nexport default function BlogPost() { ... }\n```\n\n```typescript\n\u002F\u002F After: app\u002Fblog\u002F[slug]\u002Fpage.tsx\nexport default function BlogPost() { ... }\n```\n\n### Step 4: Update Navigation\n\nReplace anchor tags with Next.js Link:\n\n```typescript\n\u002F\u002F Before (incorrect in App Router)\n\u003Ca href=\"\u002Fabout\">About\u003C\u002Fa>\n\n\u002F\u002F After (correct)\nimport Link from 'next\u002Flink';\n\u003CLink href=\"\u002Fabout\">About\u003C\u002FLink>\n```\n\n### Step 5: Clean Up Pages Directory\n\nAfter migration:\n- Remove all page files from `pages\u002F` directory\n- Keep `pages\u002Fapi\u002F` if you're not migrating API routes yet\n- Remove `_app.tsx` and `_document.tsx` (functionality moved to layout)\n- Optionally delete empty `pages\u002F` directory\n\n## Metadata Handling\n\n### Static Metadata\n\n```typescript\n\u002F\u002F app\u002Fpage.tsx or app\u002Flayout.tsx\nimport type { Metadata } from 'next';\n\nexport const metadata: Metadata = {\n  title: 'My Page',\n  description: 'Page description',\n  keywords: ['nextjs', 'react'],\n  openGraph: {\n    title: 'My Page',\n    description: 'Page description',\n    images: ['\u002Fog-image.jpg'],\n  },\n};\n```\n\n### Dynamic Metadata\n\n```typescript\n\u002F\u002F app\u002Fblog\u002F[slug]\u002Fpage.tsx\nexport async function generateMetadata({\n  params\n}: {\n  params: { slug: string }\n}): Promise\u003CMetadata> {\n  const post = await getPost(params.slug);\n\n  return {\n    title: post.title,\n    description: post.excerpt,\n  };\n}\n```\n\n## Layouts and Nesting\n\n### Creating Nested Layouts\n\n```typescript\n\u002F\u002F app\u002Flayout.tsx - Root layout\nexport default function RootLayout({ children }) {\n  return (\n    \u003Chtml>\n      \u003Cbody>\n        \u003CHeader \u002F>\n        {children}\n        \u003CFooter \u002F>\n      \u003C\u002Fbody>\n    \u003C\u002Fhtml>\n  );\n}\n\n\u002F\u002F app\u002Fblog\u002Flayout.tsx - Blog layout\nexport default function BlogLayout({ children }) {\n  return (\n    \u003Cdiv>\n      \u003CBlogSidebar \u002F>\n      \u003Cmain>{children}\u003C\u002Fmain>\n    \u003C\u002Fdiv>\n  );\n}\n```\n\n**Layout Behavior:**\n- Layouts preserve state across navigation\n- Layouts don't re-render on route changes\n- Parent layouts wrap child layouts\n- Root layout is required and wraps entire app\n\n## Routing Patterns\n\n### Dynamic Routes\n\n```typescript\n\u002F\u002F app\u002Fblog\u002F[slug]\u002Fpage.tsx\nexport default function BlogPost({\n  params\n}: {\n  params: { slug: string }\n}) {\n  return \u003Carticle>Post: {params.slug}\u003C\u002Farticle>;\n}\n```\n\n### Catch-All Routes\n\n```typescript\n\u002F\u002F app\u002Fshop\u002F[...slug]\u002Fpage.tsx - Matches \u002Fshop\u002Fa, \u002Fshop\u002Fa\u002Fb, etc.\nexport default function Shop({\n  params\n}: {\n  params: { slug: string[] }\n}) {\n  return \u003Cdiv>Path: {params.slug.join('\u002F')}\u003C\u002Fdiv>;\n}\n```\n\n### Optional Catch-All\n\n```typescript\n\u002F\u002F app\u002Fshop\u002F[[...slug]]\u002Fpage.tsx - Matches \u002Fshop AND \u002Fshop\u002Fa, \u002Fshop\u002Fa\u002Fb\n```\n\n### Route Groups\n\nGroup routes without affecting URL:\n\n```\napp\u002F\n├── (marketing)\u002F\n│   ├── about\u002F\n│   │   └── page.tsx      # \u002Fabout\n│   └── contact\u002F\n│       └── page.tsx      # \u002Fcontact\n└── (shop)\u002F\n    └── products\u002F\n        └── page.tsx      # \u002Fproducts\n```\n\n## Common Migration Pitfalls\n\n### Pitfall 1: Forgetting Root Layout HTML Tags\n\n**Wrong:**\n```typescript\nexport default function RootLayout({ children }) {\n  return \u003Cdiv>{children}\u003C\u002Fdiv>; \u002F\u002F Missing \u003Chtml> and \u003Cbody>\n}\n```\n\n**Correct:**\n```typescript\nexport default function RootLayout({ children }) {\n  return (\n    \u003Chtml lang=\"en\">\n      \u003Cbody>{children}\u003C\u002Fbody>\n    \u003C\u002Fhtml>\n  );\n}\n```\n\n### Pitfall 2: Using `next\u002Fhead` in App Router\n\n**Wrong:**\n```typescript\nimport Head from 'next\u002Fhead';\n\nexport default function Page() {\n  return (\n    \u003C>\n      \u003CHead>\u003Ctitle>Title\u003C\u002Ftitle>\u003C\u002FHead>\n      \u003Cmain>Content\u003C\u002Fmain>\n    \u003C\u002F>\n  );\n}\n```\n\n**Correct:**\n```typescript\nexport const metadata = { title: 'Title' };\n\nexport default function Page() {\n  return \u003Cmain>Content\u003C\u002Fmain>;\n}\n```\n\n### Pitfall 3: Not Removing Pages Directory\n\nAfter migrating routes, remove the old `pages\u002F` directory files to avoid confusion. The build will fail if you have conflicting routes.\n\n### Pitfall 4: Missing `page.tsx` Files\n\nRoutes are NOT accessible without a `page.tsx` file. Layouts alone don't create routes.\n\n```\napp\u002F\n├── blog\u002F\n│   ├── layout.tsx   # NOT a route\n│   └── page.tsx     # This makes \u002Fblog accessible\n```\n\n### Pitfall 5: Incorrect Link Usage\n\n**Wrong:**\n```typescript\n\u003Ca href=\"\u002Fabout\">About\u003C\u002Fa>  \u002F\u002F Works but causes full page reload\n```\n\n**Correct:**\n```typescript\nimport Link from 'next\u002Flink';\n\u003CLink href=\"\u002Fabout\">About\u003C\u002FLink>  \u002F\u002F Client-side navigation\n```\n\n## Server Components vs Client Components\n\n### Default: Server Components\n\nAll components in `app\u002F` are Server Components by default:\n\n```typescript\n\u002F\u002F app\u002Fpage.tsx - Server Component (default)\nexport default async function Page() {\n  const data = await fetch('https:\u002F\u002Fapi.example.com\u002Fdata');\n  const json = await data.json();\n\n  return \u003Cdiv>{json.title}\u003C\u002Fdiv>;\n}\n```\n\n**Benefits:**\n- Can use async\u002Fawait directly\n- Direct database\u002FAPI access\n- Zero client-side JavaScript\n- Automatic code splitting\n\n### Client Components\n\nUse `'use client'` directive when you need:\n- Interactive elements (onClick, onChange, etc.)\n- React hooks (useState, useEffect, useContext, etc.)\n- Browser APIs (window, localStorage, etc.)\n- Event listeners\n\n```typescript\n\u002F\u002F app\u002Fcomponents\u002FCounter.tsx\n'use client';\n\nimport { useState } from 'react';\n\nexport default function Counter() {\n  const [count, setCount] = useState(0);\n\n  return (\n    \u003Cbutton onClick={() => setCount(count + 1)}>\n      Count: {count}\n    \u003C\u002Fbutton>\n  );\n}\n```\n\n## Data Fetching Patterns\n\n### Server Component Data Fetching\n\n```typescript\n\u002F\u002F app\u002Fposts\u002Fpage.tsx\nasync function getPosts() {\n  const res = await fetch('https:\u002F\u002Fapi.example.com\u002Fposts', {\n    next: { revalidate: 3600 } \u002F\u002F Revalidate every hour\n  });\n  return res.json();\n}\n\nexport default async function PostsPage() {\n  const posts = await getPosts();\n\n  return (\n    \u003Cul>\n      {posts.map(post => (\n        \u003Cli key={post.id}>{post.title}\u003C\u002Fli>\n      ))}\n    \u003C\u002Ful>\n  );\n}\n```\n\n### Parallel Data Fetching\n\n```typescript\nexport default async function Page() {\n  \u002F\u002F Fetch in parallel\n  const [posts, users] = await Promise.all([\n    fetch('https:\u002F\u002Fapi.example.com\u002Fposts').then(r => r.json()),\n    fetch('https:\u002F\u002Fapi.example.com\u002Fusers').then(r => r.json()),\n  ]);\n\n  return (\u002F* render *\u002F);\n}\n```\n\n## Static Site Generation with generateStaticParams\n\n### Overview\n\n`generateStaticParams` is the App Router equivalent of `getStaticPaths` from the Pages Router. It generates static pages at build time for dynamic routes.\n\n### Basic Usage\n\n```typescript\n\u002F\u002F app\u002Fblog\u002F[id]\u002Fpage.tsx\nexport async function generateStaticParams() {\n  \u002F\u002F Return array of params to pre-render\n  return [\n    { id: '1' },\n    { id: '2' },\n    { id: '3' },\n  ];\n}\n\nexport default function BlogPost({\n  params\n}: {\n  params: { id: string }\n}) {\n  return \u003Carticle>Blog post {params.id}\u003C\u002Farticle>;\n}\n```\n\n**Key Points:**\n- Returns an array of objects with route parameter keys\n- Each object represents one page to pre-render at build time\n- Function must be exported and named `generateStaticParams`\n- Works ONLY in Server Components (no `'use client'` directive)\n- Replaces Pages Router's `getStaticPaths`\n\n### Fetching Data for Static Params\n\n```typescript\n\u002F\u002F app\u002Fblog\u002F[slug]\u002Fpage.tsx\nexport async function generateStaticParams() {\n  const posts = await fetch('https:\u002F\u002Fapi.example.com\u002Fposts').then(r => r.json());\n\n  return posts.map((post: { slug: string }) => ({\n    slug: post.slug,\n  }));\n}\n\nexport default async function BlogPost({\n  params\n}: {\n  params: { slug: string }\n}) {\n  const post = await fetch(`https:\u002F\u002Fapi.example.com\u002Fposts\u002F${params.slug}`).then(r => r.json());\n\n  return (\n    \u003Carticle>\n      \u003Ch1>{post.title}\u003C\u002Fh1>\n      \u003Cp>{post.content}\u003C\u002Fp>\n    \u003C\u002Farticle>\n  );\n}\n```\n\n### Multiple Dynamic Segments\n\n```typescript\n\u002F\u002F app\u002Fproducts\u002F[category]\u002F[id]\u002Fpage.tsx\nexport async function generateStaticParams() {\n  const categories = await getCategories();\n\n  const params = [];\n  for (const category of categories) {\n    const products = await getProducts(category.slug);\n    for (const product of products) {\n      params.push({\n        category: category.slug,\n        id: product.id,\n      });\n    }\n  }\n\n  return params;\n}\n\nexport default function ProductPage({\n  params\n}: {\n  params: { category: string; id: string }\n}) {\n  return \u003Cdiv>Category: {params.category}, Product: {params.id}\u003C\u002Fdiv>;\n}\n```\n\n### Dynamic Behavior Configuration\n\n```typescript\n\u002F\u002F app\u002Fblog\u002F[id]\u002Fpage.tsx\nexport async function generateStaticParams() {\n  return [{ id: '1' }, { id: '2' }];\n}\n\n\u002F\u002F Control behavior for non-pre-rendered paths\nexport const dynamicParams = true; \u002F\u002F default - allows runtime generation\n\u002F\u002F export const dynamicParams = false; \u002F\u002F returns 404 for non-pre-rendered paths\n\nexport default function BlogPost({\n  params\n}: {\n  params: { id: string }\n}) {\n  return \u003Carticle>Post {params.id}\u003C\u002Farticle>;\n}\n```\n\n**Options:**\n- `dynamicParams = true` (default): Non-pre-rendered paths generated on-demand\n- `dynamicParams = false`: Non-pre-rendered paths return 404\n\n### Common Patterns\n\n**Pattern 1: Simple ID-based routes**\n```typescript\nexport async function generateStaticParams() {\n  return [\n    { id: '1' },\n    { id: '2' },\n    { id: '3' },\n  ];\n}\n```\n\n**Pattern 2: Fetch from API**\n```typescript\nexport async function generateStaticParams() {\n  const items = await fetch('https:\u002F\u002Fapi.example.com\u002Fitems').then(r => r.json());\n  return items.map(item => ({ id: item.id }));\n}\n```\n\n**Pattern 3: Database query**\n```typescript\nexport async function generateStaticParams() {\n  const posts = await db.post.findMany();\n  return posts.map(post => ({ slug: post.slug }));\n}\n```\n\n### Migration from Pages Router\n\n**Before (Pages Router):**\n```typescript\n\u002F\u002F pages\u002Fblog\u002F[id].tsx\nexport async function getStaticPaths() {\n  return {\n    paths: [\n      { params: { id: '1' } },\n      { params: { id: '2' } },\n    ],\n    fallback: false,\n  };\n}\n\nexport async function getStaticProps({ params }) {\n  return { props: { id: params.id } };\n}\n```\n\n**After (App Router):**\n```typescript\n\u002F\u002F app\u002Fblog\u002F[id]\u002Fpage.tsx\nexport async function generateStaticParams() {\n  return [\n    { id: '1' },\n    { id: '2' },\n  ];\n}\n\nexport const dynamicParams = false; \u002F\u002F equivalent to fallback: false\n\nexport default function BlogPost({ params }: { params: { id: string } }) {\n  return \u003Cdiv>Post {params.id}\u003C\u002Fdiv>;\n}\n```\n\n### Common Mistakes to Avoid\n\n**❌ Wrong: Using `'use client'`**\n```typescript\n'use client'; \u002F\u002F ERROR! generateStaticParams only works in Server Components\n\nexport async function generateStaticParams() {\n  return [{ id: '1' }];\n}\n```\n\n**❌ Wrong: Using Pages Router pattern**\n```typescript\nexport async function getStaticPaths() { \u002F\u002F Wrong API!\n  return { paths: [...], fallback: false };\n}\n```\n\n**❌ Wrong: Missing export keyword**\n```typescript\nasync function generateStaticParams() { \u002F\u002F Must be exported!\n  return [{ id: '1' }];\n}\n```\n\n**✅ Correct: Clean Server Component**\n```typescript\n\u002F\u002F app\u002Fblog\u002F[id]\u002Fpage.tsx\n\u002F\u002F No 'use client' directive\n\nexport async function generateStaticParams() {\n  return [{ id: '1' }, { id: '2' }];\n}\n\nexport default function Page({ params }: { params: { id: string } }) {\n  return \u003Cdiv>Post {params.id}\u003C\u002Fdiv>;\n}\n```\n\n**CRITICAL IMPLEMENTATION NOTE:**\n\nWhen asked to \"write\" or \"implement\" `generateStaticParams`:\n- **DO** use the Edit or Write tool to modify the actual file\n- **DO** add the function to the existing page.tsx file\n- **DO** remove any TODO comments about generateStaticParams\n- **DON'T** just output code in markdown - actually implement it\n- **DON'T** show code without writing it to the file\n\n## Testing and Validation\n\nWhen migrating or building with App Router, verify:\n\n1. **Structure:**\n   - `app\u002F` directory exists\n   - Root `layout.tsx` exists with `\u003Chtml>` and `\u003Cbody>`\n   - Each route has a `page.tsx` file\n\n2. **Metadata:**\n   - No `next\u002Fhead` imports in App Router\n   - Metadata exported from pages or layouts\n   - Metadata properly typed with `Metadata` type\n\n3. **Navigation:**\n   - Using `Link` component from `next\u002Flink`\n   - Not using plain `\u003Ca>` tags for internal navigation\n\n4. **Cleanup:**\n   - No remaining page files in `pages\u002F` directory\n   - `_app.tsx` and `_document.tsx` removed\n   - Old metadata patterns removed\n\n## Quick Reference\n\n### File Structure Mapping\n\n| Pages Router | App Router | Purpose |\n|-------------|-----------|---------|\n| `pages\u002Findex.tsx` | `app\u002Fpage.tsx` | Home route |\n| `pages\u002Fabout.tsx` | `app\u002Fabout\u002Fpage.tsx` | About route |\n| `pages\u002F[id].tsx` | `app\u002F[id]\u002Fpage.tsx` | Dynamic route |\n| `pages\u002F_app.tsx` | `app\u002Flayout.tsx` | Global layout |\n| `pages\u002F_document.tsx` | `app\u002Flayout.tsx` | HTML structure |\n| `pages\u002Fapi\u002Fhello.ts` | `app\u002Fapi\u002Fhello\u002Froute.ts` | API route |\n\n### Common Commands\n\n```bash\n# Create new Next.js app with App Router\nnpx create-next-app@latest my-app\n\n# Run development server\nnpm run dev\n\n# Build for production\nnpm run build\n\n# Start production server\nnpm start\n```\n\n## Additional Resources\n\nFor more advanced routing patterns (parallel routes, intercepting routes, route handlers), refer to the `nextjs-advanced-routing` skill.\n\nFor Server vs Client component best practices and anti-patterns, refer to the `nextjs-server-client-components` and `nextjs-anti-patterns` skills.\n",{"name":5,"description":7,"allowed-tools":44},"Read, Write, Edit, Glob, Grep, Bash","main","330a71e3d12264515ce3477e446d29fd34a88a9d","template\u002Fskills-archive\u002Fnextjs-app-router-fundamentals",1,"https:\u002F\u002Fgithub.com\u002FByeongminLee\u002Fnextjs-claude-code","https:\u002F\u002Fbyeongminlee.github.io\u002Fnextjs-claude-code\u002F","https:\u002F\u002Fgithub.com\u002FByeongminLee","byeongmin.dev","2026-03-27 12:45:44",{"source":8,"skillName":5,"commands":55,"prompt":65,"zipAvailable":66},[56,59,62],{"tool":57,"command":58},"npx","npx skills add ByeongminLee\u002Fnextjs-claude-code --skill nextjs-app-router-fundamentals",{"tool":60,"command":61},"bunx","bunx skills add ByeongminLee\u002Fnextjs-claude-code --skill nextjs-app-router-fundamentals",{"tool":63,"command":64},"pnpm","pnpm dlx skills add ByeongminLee\u002Fnextjs-claude-code --skill nextjs-app-router-fundamentals","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FByeongminLee\u002Fnextjs-claude-code\u002Fblob\u002Fmain\u002Ftemplate\u002Fskills-archive\u002Fnextjs-app-router-fundamentals\u002FSKILL.md",true,[68],{"path":69,"resourceType":70,"resourceTypeDesc":71,"sizeBytes":72,"sourceHtmlUrl":73},"_AIWF_IMPORT.json","REFERENCE","参考文档",397,"https:\u002F\u002Fgithub.com\u002FiDorgham\u002FWorkspace-Factory\u002Fblob\u002Fmaster\u002Ffactory\u002Flibrary\u002Fskills\u002Fgithub_imports\u002Fauth-implementation-patterns\u002F_AIWF_IMPORT.json",[75,91,99,129,157,196],{"skillNo":76,"name":77,"nameZh":6,"description":78,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":79,"categories":80,"keywords":81,"publishedAt":39},"01M6E263DRDCZ5AX01N6MDYC6Z","zustand","Zustand state management guide. Use when working with store code (src\u002Fstore\u002F**), implementing actions, managing state, or creating slices. Triggers on Zustand store development, state management questions, or action implementation.","https:\u002F\u002Fgithub.com\u002FByeongminLee\u002Fnextjs-claude-code\u002Fblob\u002Fmain\u002Ftemplate\u002Fskills-archive\u002Fzustand\u002FSKILL.md",[],[77,82,83,84,85,29,23,86,87,88,89,90,38],"triggers","state management","zustand state","implementation","management","src","actions","state","code",{"skillNo":92,"name":93,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":96,"publishedAt":39},"01M6E260QFP3ZMXY2Y6KTGZYXS","web-vitals","https:\u002F\u002Fgithub.com\u002FByeongminLee\u002Fnextjs-claude-code\u002Fblob\u002Fmain\u002Ftemplate\u002Fskills-archive\u002Fweb-vitals\u002FSKILL.md",[],[97,98],"web vitals","web",{"skillNo":100,"name":101,"nameZh":6,"description":102,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":103,"categories":104,"keywords":110,"publishedAt":39},"01M6E25QEKXHH092S5RB0GKM0K","vercel-storage","Vercel storage expert guidance — Blob, Edge Config, and Marketplace storage (Neon Postgres, Upstash Redis). Use when choosing, configuring, or using data storage with Vercel applications.","https:\u002F\u002Fgithub.com\u002FByeongminLee\u002Fnextjs-claude-code\u002Fblob\u002Fmain\u002Ftemplate\u002Fskills-archive\u002Fvercel-storage\u002FSKILL.md",[105],{"categoryNo":106,"categoryName":107,"taxonomyType":108,"taxonomyTypeDesc":109},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",[111,112,113,114,115,116,117,21,118,119,120,121,20,122,123,124,125,126,127,128],"vercel","vercel storage","storage","supabase","api","mongodb","SET","database","auth","migrate","click","neon","prisma","postgres","expert","up","auto","configure",{"skillNo":130,"name":131,"nameZh":6,"description":132,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":133,"categories":134,"keywords":141,"publishedAt":39},"01M6E25EC9YM4QM0KBQ2W5R1SC","vercel-functions","Vercel Functions expert guidance — Serverless Functions, Edge Functions, Fluid Compute, streaming, Cron Jobs, and runtime configuration. Use when configuring, debugging, or optimizing server-side code running on Vercel.","https:\u002F\u002Fgithub.com\u002FByeongminLee\u002Fnextjs-claude-code\u002Fblob\u002Fmain\u002Ftemplate\u002Fskills-archive\u002Fvercel-functions\u002FSKILL.md",[135,136],{"categoryNo":106,"categoryName":107,"taxonomyType":108,"taxonomyTypeDesc":109},{"categoryNo":137,"categoryName":138,"taxonomyType":139,"taxonomyTypeDesc":140},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[142,111,143,144,145,146,147,148,20,122,149,150,22,151,152,153,154,155,156,125],"functions","vercel functions","local","shared","project","time","apps","express","vercel ai sdk","loop","server","logs","streaming","delete","create",{"skillNo":158,"name":159,"nameZh":6,"description":160,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":161,"categories":162,"keywords":178,"publishedAt":39},"01M6E25873YRYP96MSQK7E2D9X","ui-ux-pro-max","UI\u002FUX design intelligence for web and mobile. Includes 50+ styles, 161 color palettes, 57 font pairings, 161 product types, 99 UX guidelines, and 25 chart types across 10 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind, shadcn\u002Fui, and HTML\u002FCSS). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, and check UI\u002FUX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, and mobile app. Elements: button, modal, navbar, sidebar, card, table, form, and chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, and flat design. Topics: color systems, accessibility, animation, layout, typography, font pairing, spacing, interaction states, shadow, and gradient. Integrations: shadcn\u002Fui MCP for component search and examples.","https:\u002F\u002Fgithub.com\u002FByeongminLee\u002Fnextjs-claude-code\u002Fblob\u002Fmain\u002Ftemplate\u002Fskills-archive\u002Fui-ux-pro-max\u002FSKILL.md",[163,166,169,172,175],{"categoryNo":164,"categoryName":165,"taxonomyType":108,"taxonomyTypeDesc":109},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":167,"categoryName":168,"taxonomyType":108,"taxonomyTypeDesc":109},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":170,"categoryName":171,"taxonomyType":108,"taxonomyTypeDesc":109},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":173,"categoryName":174,"taxonomyType":139,"taxonomyTypeDesc":140},"01JBSEEDCAT000000000000032","设计师",{"categoryNo":176,"categoryName":177,"taxonomyType":139,"taxonomyTypeDesc":140},"01JBSEEDCAT000000000000033","数据分析师",[179,180,181,182,183,184,185,186,20,187,188,189,190,191,192,193,194,88,195,156],"ui ux pro max","ui","ux","max","css","MCP","design","react","card","chart","fix","projects","plan","improve","Tailwind","Animation","search",{"skillNo":197,"name":198,"nameZh":6,"description":199,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":200,"categories":201,"keywords":202,"publishedAt":39},"01M6E251G3FJSRB9019V20QK9X","turborepo","Turborepo monorepo build system guidance. Triggers on: turbo.json, task pipelines,\ndependsOn, caching, remote cache, the \"turbo\" CLI, --filter, --affected, CI optimization, environment\nvariables, internal packages, monorepo structure\u002Fbest practices, and boundaries.\n\nUse when user: configures tasks\u002Fworkflows\u002Fpipelines, creates packages, sets up\nmonorepo, shares code between apps, runs changed\u002Faffected packages, debugs cache,\nor has apps\u002Fpackages directories.","https:\u002F\u002Fgithub.com\u002FByeongminLee\u002Fnextjs-claude-code\u002Fblob\u002Fmain\u002Ftemplate\u002Fskills-archive\u002Fturborepo\u002FSKILL.md",[],[198,203,29,204,205,148,82,206,207,126,208,209,210,211,212,213,90,214,30,215],"cli","filter","environment variables","caching","structure","environment","monorepo","system","canary","Optimization","ci","packages","workflows"]