nextjs-app-router
giuseppe-trisciuoglio/developer-kit
Patterns and code examples for Next.js 16+ App Router architecture with Server Components, Server Actions, and caching.
What is nextjs-app-router?
Provides patterns for building Next.js 16+ applications using App Router, including Server Components, Client Components, Server Actions, Route Handlers, caching with "use cache" directive, parallel routes, and Next.js 16 async APIs. Use when creating or migrating App Router projects, implementing form handling, building API endpoints, or configuring advanced routing patterns.
- Build Server Components (default) and Client Components with "use client" directive
- Create Server Actions for form submissions and mutations with revalidation
- Define Route Handlers (route.ts) for API endpoints with GET, POST, and dynamic segments
- Configure explicit caching with "use cache", cacheLife, and cacheTag directives
- Set up parallel routes using @slot convention and intercepting routes
- Work with App Router file conventions (layout.tsx, page.tsx, loading.tsx, error.tsx, not-found.tsx)
How to install nextjs-app-router
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill nextjs-app-router- Node.js 18+ installed
- Basic React and TypeScript knowledge
- Familiarity with async/await and modern JavaScript
How to use nextjs-app-router
- 1.Create a new Next.js 16 project using npx create-next-app@latest with --app flag and --turbopack
- 2.Identify whether components need interactivity (use Client Component with "use client") or can be Server Components (default)
- 3.For forms and mutations, create Server Actions in separate files with "use server" directive and use useActionState in Client Components
- 4.Define API endpoints using route.ts files in api folders with GET, POST, and other HTTP methods
- 5.Add caching directives ("use cache", cacheLife, cacheTag) to frequently accessed pages or data fetches
- 6.Implement loading states with loading.tsx files and error boundaries with error.tsx files
- 7.Use parallel routes with @slot convention in layout.tsx for complex dashboard or multi-section layouts
Use cases
- Creating a new Next.js 16 project with App Router and TypeScript
- Building a form with Server Action for user registration or blog post submission
- Implementing an API endpoint with Route Handlers for CRUD operations
- Setting up caching strategies for product pages or frequently accessed data
- Creating dashboard layouts with parallel routes for team and analytics sections
- Next.js developers building modern React applications
- Full-stack developers implementing server-side form handling and mutations
- API developers creating Route Handlers for backend endpoints
- Teams migrating from Pages Router to App Router architecture
- Developers optimizing performance with caching and Suspense boundaries
nextjs-app-router FAQ
Start with Server Components (the default). Only use Client Components when you need React hooks (useState, useEffect), browser APIs (window, document), event handlers (onClick, onSubmit), or client-only libraries.
Create a Server Action in a separate file with "use server" directive, then use it with useActionState in a Client Component form. The Server Action receives FormData and can validate, mutate data, and revalidate paths.
"use cache" (Next.js 16+) enables explicit caching for Server Components. Use cacheLife() to set duration (e.g., "hours") and cacheTag() to tag cache for on-demand revalidation. Use it for frequently accessed data like product pages.
Create a route.ts file in an api folder with exported async functions (GET, POST, etc.). Use NextRequest and NextResponse for handling requests and responses. Dynamic segments use [param] syntax.
All Next.js APIs (cookies, headers, params, searchParams) are now async and return Promises. You must await them in Server Components. See references/nextjs16-migration.md for migration details.
Full instructions (SKILL.md)
Source of truth, from giuseppe-trisciuoglio/developer-kit.
name: nextjs-app-router
description: Provides patterns and code examples for building Next.js 16+ applications with App Router architecture. Use when creating projects with App Router, implementing Server Components and Client Components ("use client"), creating Server Actions for forms, building Route Handlers (route.ts), configuring caching with "use cache" directive (cacheLife, cacheTag), setting up parallel routes (@slot) or intercepting routes, migrating to proxy.ts, or working with App Router file conventions (layout.tsx, page.tsx, loading.tsx, error.tsx).
allowed-tools: Read, Write, Edit, Bash
Next.js App Router (Next.js 16+)
Build modern React applications using Next.js 16+ with App Router architecture.
Overview
This skill provides patterns for Server Components (default) and Client Components ("use client"), Server Actions for mutations and form handling, Route Handlers for API endpoints, explicit caching with "use cache" directive, parallel and intercepting routes, and Next.js 16 async APIs and proxy.ts.
When to Use
Activate when user requests involve:
- "Create a Next.js 16 project", "Set up App Router"
- "Server Component", "Client Component", "use client"
- "Server Action", "form submission", "mutation"
- "Route Handler", "API endpoint", "route.ts"
- "use cache", "cacheLife", "cacheTag", "revalidation"
- "parallel routes", "
@slot", "intercepting routes" - "proxy.ts", "migrate from middleware.ts"
- "layout.tsx", "page.tsx", "loading.tsx", "error.tsx", "not-found.tsx"
- "generateMetadata", "next/image", "next/font"
Quick Reference
| File | Purpose | Directive | Purpose |
|---|---|---|---|
page.tsx | Route page | "use server" | Server Action function |
layout.tsx | Shared layout | "use client" | Client Component boundary |
loading.tsx | Suspense loading | "use cache" | Explicit caching (Next.js 16) |
error.tsx | Error boundary | ||
not-found.tsx | 404 page | ||
route.ts | API Route Handler | ||
proxy.ts | Routing boundary |
Instructions
Create New Project
npx create-next-app@latest my-app --typescript --tailwind --app --turbopack
Server Component
Server Components are the default in App Router. They run on the server and can use async/await.
// app/users/page.tsx
async function getUsers() {
const apiUrl = process.env.API_URL;
const res = await fetch(`${apiUrl}/users`);
return res.json();
}
export default async function UsersPage() {
const users = await getUsers();
return <main>{users.map(user => <UserCard key={user.id} user={user} />)}</main>;
}
Client Component
Add "use client" when using hooks, browser APIs, or event handlers.
"use client";
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>;
}
Server Action
Define actions in separate files with "use server" directive.
// app/actions.ts
"use server";
import { revalidatePath } from "next/cache";
export async function createUser(formData: FormData) {
const name = formData.get("name") as string;
const email = formData.get("email") as string;
await db.user.create({ data: { name, email } });
revalidatePath("/users");
}
Use with forms in Client Components:
"use client";
import { useActionState } from "react";
import { createUser } from "./actions";
export default function UserForm() {
const [state, formAction, pending] = useActionState(createUser, {});
return (
<form action={formAction}>
<input name="name" />
<input name="email" type="email" />
<button type="submit" disabled={pending}>{pending ? "Creating..." : "Create"}</button>
</form>
);
}
See references/server-actions.md for Zod validation, optimistic updates, and advanced patterns.
Configure Caching
Use "use cache" directive for explicit caching (Next.js 16+).
"use cache";
import { cacheLife, cacheTag } from "next/cache";
export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
cacheTag(`product-${id}`);
cacheLife("hours");
const product = await fetchProduct(id);
return <ProductDetail product={product} />;
}
See references/caching-strategies.md for cache profiles, on-demand revalidation, and advanced patterns.
Route Handler
// app/api/users/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
return NextResponse.json(await db.user.findMany());
}
export async function POST(request: NextRequest) {
const body = await request.json();
return NextResponse.json(await db.user.create({ data: body }), { status: 201 });
}
Dynamic segments use [param]:
// app/api/users/[id]/route.ts
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const user = await db.user.findUnique({ where: { id } });
if (!user) return NextResponse.json({ error: "Not found" }, { status: 404 });
return NextResponse.json(user);
}
Next.js 16 Async APIs
All Next.js APIs are async in version 16.
import { cookies, headers } from "next/headers";
export default async function Page() {
const cookieStore = await cookies();
const headersList = await headers();
const session = cookieStore.get("session")?.value;
const userAgent = headersList.get("user-agent");
return <div>...</div>;
}
Params and searchParams are also Promise-based:
export default async function Page({
params,
searchParams,
}: {
params: Promise<{ slug: string }>;
searchParams: Promise<{ sort?: string }>;
}) {
const { slug } = await params;
const { sort } = await searchParams;
// ...
}
See references/nextjs16-migration.md for migration guide and proxy.ts configuration.
Parallel Routes
Use @folder convention for parallel route slots.
// app/dashboard/layout.tsx
export default function DashboardLayout({ children, team, analytics }: Record<string, React.ReactNode>) {
return (
<div>
{children}
<div className="grid grid-cols-2">{team}{analytics}</div>
</div>
);
}
// app/dashboard/@team/page.tsx
export default function TeamPage() { return <div>Team Section</div>; }
// app/dashboard/@analytics/page.tsx
export default function AnalyticsPage() { return <div>Analytics Section</div>; }
See references/routing-patterns.md for intercepting routes, route groups, and dynamic routes.
Best Practices
Server vs Client Decision:
- Start with Server Component (default)
- Use Client Component only for: React hooks (useState, useEffect), browser APIs (window, document), event handlers (onClick, onSubmit), or client-only libraries
Data Fetching:
- Fetch in Server Components when possible
- Use React's
cache()for deduplication - Parallelize independent fetches
- Add Suspense boundaries with
loading.tsx
Performance Checklist:
- Use
loading.tsxfor Suspense boundaries - Use
next/imagefor optimized images - Use
next/fontfor font optimization - Add
error.tsxandnot-found.tsxfor error handling
Examples
Example 1: Blog Post Form with Server Action
Input: Create a form to submit blog posts with Zod validation
Output:
// app/blog/actions.ts
"use server";
import { z } from "zod";
import { revalidatePath } from "next/cache";
const schema = z.object({ title: z.string().min(5), content: z.string().min(10) });
export async function createPost(formData: FormData) {
const parsed = schema.safeParse({ title: formData.get("title"), content: formData.get("content") });
if (!parsed.success) return { errors: parsed.error.flatten().fieldErrors };
await db.post.create({ data: parsed.data });
revalidatePath("/blog");
return { success: true };
}
// app/blog/new/page.tsx
"use client";
import { useActionState } from "react";
import { createPost } from "../actions";
export default function NewPostPage() {
const [state, formAction, pending] = useActionState(createPost, {});
return (
<form action={formAction}>
<input name="title" placeholder="Title" />
{state.errors?.title && <span>{state.errors.title[0]}</span>}
<textarea name="content" placeholder="Content" />
{state.errors?.content && <span>{state.errors.content[0]}</span>}
<button type="submit" disabled={pending}>{pending ? "Publishing..." : "Publish"}</button>
</form>
);
}
Example 2: Cached Product Page
Input: Create a cached product page with on-demand revalidation
Output:
// app/products/[id]/page.tsx
"use cache";
import { cacheLife, cacheTag } from "next/cache";
export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
cacheTag(`product-${id}`, "products");
cacheLife("hours");
const product = await db.product.findUnique({ where: { id } });
if (!product) notFound();
return <article><h1>{product.name}</h1><p>{product.description}</p></article>;
}
// app/api/revalidate/route.ts
import { revalidateTag } from "next/cache";
import { NextResponse } from "next/server";
export async function POST(request: Request) {
const { tag } = await request.json();
revalidateTag(tag);
return NextResponse.json({ revalidated: true });
}
Example 3: Dashboard with Parallel Routes
Input: Create a dashboard with sidebar and stats areas
Output:
// app/dashboard/layout.tsx
export default function DashboardLayout({ children, sidebar, stats }: Record<string, React.ReactNode>) {
return (
<div className="flex">
<aside className="w-64">{sidebar}</aside>
<main className="flex-1"><div className="grid grid-cols-3">{stats}</div>{children}</main>
</div>
);
}
// app/dashboard/@sidebar/page.tsx
export default function Sidebar() { return <nav>{/* Navigation links */}</nav>; }
// app/dashboard/@stats/page.tsx
export default async function Stats() {
const stats = await fetchStats();
return <><div>Users: {stats.users}</div><div>Orders: {stats.orders}</div></>;
}
Constraints and Warnings
Constraints:
- Server Components cannot use browser APIs or React hooks
- Client Components cannot be async (no direct data fetching)
cookies(),headers(),draftMode()are async in Next.js 16paramsandsearchParamsare Promise-based in Next.js 16- Server Actions must be defined with
"use server"directive
Warnings:
- Using
awaitin a Client Component causes a build error - Accessing
windowordocumentin Server Components throws an error - Forgetting to
awaitcookies() or headers() in Next.js 16 returns a Promise instead of the value - Server Actions without proper validation can expose the database to unauthorized access
- External Data Fetching: Server Components that
fetch()third-party URLs process untrusted content — always validate, sanitize, and type-check responses; use environment variables for API URLs rather than hardcoding them
References
- references/app-router-fundamentals.md — Server/Client Components, file conventions, navigation
- references/routing-patterns.md — Parallel routes, intercepting routes, route groups
- references/caching-strategies.md — "use cache", cacheLife, cacheTag, revalidation
- references/server-actions.md — Server Actions, useActionState, validation, optimistic updates
- references/nextjs16-migration.md — Async APIs, proxy.ts, Turbopack, config
- references/data-fetching.md — Data patterns, Suspense, streaming
- references/metadata-api.md — generateMetadata, OpenGraph, sitemap
Related skills
More from giuseppe-trisciuoglio/developer-kit and the wider catalog.

nextjs-authentication
Provides authentication implementation patterns for Next.js 15+ App Router using Auth.js 5 (NextAuth.js). Use when setting up authentication flows, implementing protected routes, managing sessions in Server Components and Server Actions, configuring OAuth providers, implementing role-based access control, or handling sign-in/sign-out flows in Next.js applications.

nextjs-code-review
Provides comprehensive code review capability for Next.js applications, validates Server Components, Client Components, Server Actions, caching strategies, metadata, API routes, middleware, and performance patterns. Use when reviewing Next.js App Router code changes, before merging pull requests, after implementing new features, or for architecture validation. Triggers on "review Next.js code", "Next.js code review", "check my Next.js app".

nextjs-data-fetching
Provides Next.js App Router data fetching patterns including SWR and React Query integration, parallel data fetching, Incremental Static Regeneration (ISR), revalidation strategies, and error boundaries. Use when implementing data fetching in Next.js applications, choosing between server and client fetching, setting up caching strategies, or handling loading and error states.

nextjs-deployment
Provides comprehensive patterns for deploying Next.js applications to production. Use when configuring Docker containers, setting up GitHub Actions CI/CD pipelines, managing environment variables, implementing preview deployments, or setting up monitoring and logging for Next.js applications. Covers standalone output, multi-stage Docker builds, health checks, OpenTelemetry instrumentation, and production best practices.

nextjs-performance
Expert Next.js performance optimization for Core Web Vitals, images, fonts, caching, and Server Components.

notebooklm
Enables interaction with Google NotebookLM for advanced RAG (Retrieval-Augmented Generation) capabilities via the notebooklm-mcp-cli tool. Use when querying project documentation stored in NotebookLM, managing research notebooks and sources, retrieving AI-synthesized information, generating audio podcasts or reports from notebooks, or performing contextual queries against curated knowledge bases. Triggers on "notebooklm", "nlm", "notebook query", "research notebook", "query documentation in notebooklm".