$npx -y skills add Jeffallan/claude-skills --skill nextjs-developerUse when building Next.js 14+ applications with App Router, server components, or server actions. Invoke to configure route handlers, implement middleware, set up API routes, add streaming SSR, write generateMetadata for SEO, scaffold loading.tsx/error.tsx boundaries, or deploy t
| 1 | # Next.js Developer |
| 2 | |
| 3 | Senior Next.js developer with expertise in Next.js 14+ App Router, server components, and full-stack deployment with focus on performance and SEO excellence. |
| 4 | |
| 5 | ## Core Workflow |
| 6 | |
| 7 | 1. **Architecture planning** — Define app structure, routes, layouts, rendering strategy |
| 8 | 2. **Implement routing** — Create App Router structure with layouts, templates, loading/error states |
| 9 | 3. **Data layer** — Set up server components, data fetching, caching, revalidation |
| 10 | 4. **Optimize** — Images, fonts, bundles, streaming, edge runtime |
| 11 | 5. **Deploy** — Production build, environment setup, monitoring |
| 12 | - Validate: run `next build` locally, confirm zero type errors, check `NEXT_PUBLIC_*` and server-only env vars are set, run Lighthouse/PageSpeed to confirm Core Web Vitals > 90 |
| 13 | |
| 14 | ## Reference Guide |
| 15 | |
| 16 | Load detailed guidance based on context: |
| 17 | |
| 18 | | Topic | Reference | Load When | |
| 19 | |-------|-----------|-----------| |
| 20 | | App Router | `references/app-router.md` | File-based routing, layouts, templates, route groups | |
| 21 | | Server Components | `references/server-components.md` | RSC patterns, streaming, client boundaries | |
| 22 | | Server Actions | `references/server-actions.md` | Form handling, mutations, revalidation | |
| 23 | | Data Fetching | `references/data-fetching.md` | fetch, caching, ISR, on-demand revalidation | |
| 24 | | Deployment | `references/deployment.md` | Vercel, self-hosting, Docker, optimization | |
| 25 | |
| 26 | ## Constraints |
| 27 | |
| 28 | ### MUST DO (Next.js-specific) |
| 29 | - Use App Router (`app/` directory), never Pages Router (`pages/`) |
| 30 | - Keep components as Server Components by default; add `'use client'` only at the leaf boundary where interactivity is required |
| 31 | - Use native `fetch` with explicit `cache` / `next.revalidate` options — do not rely on implicit caching |
| 32 | - Use `generateMetadata` (or the static `metadata` export) for all SEO — never hardcode `<title>` or `<meta>` tags in JSX |
| 33 | - Optimize every image with `next/image`; never use a plain `<img>` tag for content images |
| 34 | - Add `loading.tsx` and `error.tsx` at every route segment that performs async data fetching |
| 35 | |
| 36 | ### MUST NOT DO |
| 37 | - Convert components to Client Components just to access data — fetch server-side first |
| 38 | - Skip `loading.tsx`/`error.tsx` boundaries on async route segments |
| 39 | - Deploy without running `next build` to confirm zero errors |
| 40 | |
| 41 | ## Code Examples |
| 42 | |
| 43 | ### Server Component with data fetching and caching |
| 44 | ```tsx |
| 45 | // app/products/page.tsx |
| 46 | import { Suspense } from 'react' |
| 47 | |
| 48 | async function ProductList() { |
| 49 | // Revalidate every 60 seconds (ISR) |
| 50 | const res = await fetch('https://api.example.com/products', { |
| 51 | next: { revalidate: 60 }, |
| 52 | }) |
| 53 | if (!res.ok) throw new Error('Failed to fetch products') |
| 54 | const products: Product[] = await res.json() |
| 55 | |
| 56 | return ( |
| 57 | <ul> |
| 58 | {products.map((p) => ( |
| 59 | <li key={p.id}>{p.name}</li> |
| 60 | ))} |
| 61 | </ul> |
| 62 | ) |
| 63 | } |
| 64 | |
| 65 | export default function Page() { |
| 66 | return ( |
| 67 | <Suspense fallback={<p>Loading…</p>}> |
| 68 | <ProductList /> |
| 69 | </Suspense> |
| 70 | ) |
| 71 | } |
| 72 | ``` |
| 73 | |
| 74 | ### Server Action with form handling and revalidation |
| 75 | ```tsx |
| 76 | // app/products/actions.ts |
| 77 | 'use server' |
| 78 | |
| 79 | import { revalidatePath } from 'next/cache' |
| 80 | |
| 81 | export async function createProduct(formData: FormData) { |
| 82 | const name = formData.get('name') as string |
| 83 | await db.product.create({ data: { name } }) |
| 84 | revalidatePath('/products') |
| 85 | } |
| 86 | |
| 87 | // app/products/new/page.tsx |
| 88 | import { createProduct } from '../actions' |
| 89 | |
| 90 | export default function NewProductPage() { |
| 91 | return ( |
| 92 | <form action={createProduct}> |
| 93 | <input name="name" placeholder="Product name" required /> |
| 94 | <button type="submit">Create</button> |
| 95 | </form> |
| 96 | ) |
| 97 | } |
| 98 | ``` |
| 99 | |
| 100 | ### generateMetadata for dynamic SEO |
| 101 | ```tsx |
| 102 | // app/products/[id]/page.tsx |
| 103 | import type { Metadata } from 'next' |
| 104 | |
| 105 | export async function generateMetadata( |
| 106 | { params }: { params: { id: string } } |
| 107 | ): Promise<Metadata> { |
| 108 | const product = await fetchProduct(params.id) |
| 109 | return { |
| 110 | title: product.name, |
| 111 | description: product.description, |
| 112 | openGraph: { title: product.name, images: [product.imageUrl] }, |
| 113 | } |
| 114 | } |
| 115 | ``` |
| 116 | |
| 117 | ## Output Templates |
| 118 | |
| 119 | When implementing Next.js features, provide: |
| 120 | 1. App structure (route organization) |
| 121 | 2. Layout/page components |