nextjs

SKILL.md

Next.js Skill

Provides comprehensive Next.js development capabilities for modern web applications.

When to Use This Skill

Activate this skill when working with:

  • Next.js App Router
  • Server Components and Client Components
  • API Routes and Server Actions
  • Static Site Generation (SSG)
  • Server-Side Rendering (SSR)

Project Structure (App Router)

``` app/ ├── layout.tsx # Root layout ├── page.tsx # Home page ├── loading.tsx # Loading UI ├── error.tsx # Error handling ├── not-found.tsx # 404 page ├── globals.css ├── agents/ │ ├── page.tsx # /agents │ ├── [id]/ │ │ ├── page.tsx # /agents/[id] │ │ └── edit/ │ │ └── page.tsx # /agents/[id]/edit │ └── new/ │ └── page.tsx # /agents/new ├── api/ │ └── agents/ │ ├── route.ts # /api/agents │ └── [id]/ │ └── route.ts # /api/agents/[id] └── (dashboard)/ # Route group ├── layout.tsx └── settings/ └── page.tsx ```

Server Components (Default)

```tsx // app/agents/page.tsx - Server Component async function AgentsPage() { // Direct database access (no API needed) const agents = await db.query('SELECT * FROM agents');

return ( Agents {agents.map(agent => ( {agent.name} ))} ); }

export default AgentsPage; ```

Client Components

```tsx // components/AgentSelector.tsx 'use client';

import { useState } from 'react';

export function AgentSelector({ agents }: { agents: Agent[] }) { const [selected, setSelected] = useState<string | null>(null);

return ( <select value={selected || ''} onChange={(e) => setSelected(e.target.value)} > Select an agent {agents.map(agent => ( {agent.name} ))} ); } ```

Data Fetching

Server Component Data Fetching

```tsx // Automatic request deduplication async function getAgent(id: string) { const res = await fetch(${process.env.API_URL}/agents/${id}, { cache: 'force-cache', // Default: cache forever // cache: 'no-store', // Never cache // next: { revalidate: 60 } // Revalidate every 60s }); return res.json(); }

export default async function AgentPage({ params }: { params: { id: string } }) { const agent = await getAgent(params.id); return ; } ```

Revalidation

```tsx // Time-based revalidation export const revalidate = 60; // Revalidate every 60 seconds

// On-demand revalidation import { revalidatePath, revalidateTag } from 'next/cache';

async function updateAgent(id: string, data: FormData) { 'use server'; await db.update('agents', id, data); revalidatePath('/agents'); revalidateTag('agents'); } ```

Server Actions

```tsx // app/agents/new/page.tsx import { redirect } from 'next/navigation';

async function createAgent(formData: FormData) { 'use server';

const name = formData.get('name') as string; const type = formData.get('type') as string;

await db.insert('agents', { name, type });

revalidatePath('/agents'); redirect('/agents'); }

export default function NewAgentPage() { return ( Claude GPT Create Agent ); } ```

API Routes

```tsx // app/api/agents/route.ts import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) { const searchParams = request.nextUrl.searchParams; const type = searchParams.get('type');

const agents = await db.query( 'SELECT * FROM agents WHERE type = $1', [type] );

return NextResponse.json(agents); }

export async function POST(request: NextRequest) { const body = await request.json();

const agent = await db.insert('agents', body);

return NextResponse.json(agent, { status: 201 }); }

// app/api/agents/[id]/route.ts export async function GET( request: NextRequest, { params }: { params: { id: string } } ) { const agent = await db.query('SELECT * FROM agents WHERE id = $1', [params.id]);

if (!agent) { return NextResponse.json({ error: 'Not found' }, { status: 404 }); }

return NextResponse.json(agent); } ```

Layouts and Loading States

```tsx // app/layout.tsx export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( Navigation {children} Footer ); }

// app/agents/loading.tsx export default function Loading() { return Loading agents...; }

// app/agents/error.tsx 'use client';

export default function Error({ error, reset, }: { error: Error; reset: () => void; }) { return ( Something went wrong! <button onClick={() => reset()}>Try again ); } ```

Middleware

```tsx // middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) { // Authentication check const token = request.cookies.get('token');

if (!token && request.nextUrl.pathname.startsWith('/dashboard')) { return NextResponse.redirect(new URL('/login', request.url)); }

// Add headers const response = NextResponse.next(); response.headers.set('x-custom-header', 'value');

return response; }

export const config = { matcher: ['/dashboard/:path*', '/api/:path*'], }; ```

Environment Variables

```bash

.env.local

DATABASE_URL=postgresql://... API_URL=http://localhost:8000

Public (exposed to browser)

NEXT_PUBLIC_APP_URL=http://localhost:3000 ```

```tsx // Server-only const dbUrl = process.env.DATABASE_URL;

// Client-accessible const appUrl = process.env.NEXT_PUBLIC_APP_URL; ```

Build Commands

```bash

Development

npm run dev

Production build

npm run build npm start

Static export

npm run build

next.config.js: output: 'export'

```

Weekly Installs
22
GitHub Stars
9
First Seen
Jan 24, 2026
Installed on
claude-code18
gemini-cli18
opencode18
codex17
antigravity16
cursor16