Official 2026 Reference • Next.js 15+ & React 19

Next.js App Router Cheat Sheet

Copy production-grade code snippets for App Router routing files, Server Actions, React 19 form binding, cache revalidation, middleware, and metadata.

Page Component (app/blog/[slug]/page.tsx)

Async Server Component with async params & searchParams handling (Next.js 15 spec).

Docs
// app/blog/[slug]/page.tsx
import { notFound } from "next/navigation";

interface PageProps {
  params: Promise<{ slug: string }>;
  searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
}

export default async function BlogPostPage({ params, searchParams }: PageProps) {
  // In Next.js 15+, params and searchParams are Promises that must be awaited
  const { slug } = await params;
  const query = await searchParams;

  if (!slug) notFound();

  return (
    <article className="p-8">
      <h1 className="text-4xl font-black">Article: {slug}</h1>
      <p className="mt-2 text-gray-500">Category Filter: {query.filter || "all"}</p>
    </article>
  );
}

Root Layout (app/layout.tsx)

Top-level shell defining <html> and <body>. Preserved across route transitions.

Docs
// app/layout.tsx
import type { Metadata } from "next";

export const metadata: Metadata = {
  title: "DevDossier | Developer Engineering Hub",
  description: "High-performance web development, UI engineering, and technical guides.",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en" className="dark">
      <body className="antialiased bg-slate-950 text-white min-h-screen">
        {children}
      </body>
    </html>
  );
}

Route Handler API (app/api/posts/route.ts)

RESTful HTTP API endpoints returning JSON with custom status codes.

Docs
// app/api/posts/route.ts
import { NextResponse, type NextRequest } from "next/server";

export async function GET(request: NextRequest) {
  const { searchParams } = new URL(request.url);
  const category = searchParams.get("category");

  return NextResponse.json(
    {
      success: true,
      category: category || "all",
      data: [{ id: "post-1", title: "Next.js 15 App Router" }],
    },
    { status: 200 }
  );
}

export async function POST(request: NextRequest) {
  const body = await request.json();
  return NextResponse.json({ created: true, body }, { status: 201 });
}

Server Action Mutation & Cache Invalidation

Server-side mutation function with revalidateTag and revalidatePath.

Docs
// app/actions/updateProfile.ts
"use server";

import { revalidateTag, revalidatePath } from "next/cache";

export async function updateProfile(prevState: any, formData: FormData) {
  const username = formData.get("username") as string;

  if (!username || username.length < 3) {
    return { error: "Username must be at least 3 characters long" };
  }

  // Perform database write
  // await db.user.update({ where: { id }, data: { username } });

  // Invalidate specific cache tags & paths
  revalidateTag("user-profile", "max");
  revalidatePath("/dashboard");

  return { success: true, username };
}

React 19 useActionState Form Binding

Bind Server Action with pending state & action result using React 19 hooks.

Docs
// components/ProfileForm.tsx
"use client";

import { useActionState } from "react";
import { updateProfile } from "@/app/actions/updateProfile";

export default function ProfileForm() {
  const [state, formAction, isPending] = useActionState(updateProfile, null);

  return (
    <form action={formAction} className="space-y-4 max-w-md">
      <input
        name="username"
        placeholder="Enter Username"
        required
        className="w-full rounded-xl border p-3 bg-slate-900 text-white"
      />
      <button
        type="submit"
        disabled={isPending}
        className="w-full rounded-xl bg-blue-600 py-3 font-bold text-white hover:bg-blue-700 disabled:opacity-50"
      >
        {isPending ? "Saving..." : "Update Profile"}
      </button>

      {state?.error && <p className="text-red-400 text-xs font-semibold">{state.error}</p>}
      {state?.success && <p className="text-emerald-400 text-xs font-semibold">Updated to {state.username}</p>}
    </form>
  );
}

Tagged Data Fetching with Revalidation

Configure fetch caching behavior and tags for revalidateTag().

Docs
// lib/getPosts.ts
export async function getPosts() {
  const res = await fetch("https://api.example.com/posts", {
    next: {
      revalidate: 3600, // Revalidate every 1 hour (ISR)
      tags: ["posts-list"], // Tagged for instant on-demand purge
    },
  });

  if (!res.ok) throw new Error("Failed to fetch posts");
  return res.json();
}

Edge Middleware & Protected Routes

Execute request interception before route handlers run.

Docs
// middleware.ts
import { NextResponse, type NextRequest } from "next/server";

export function middleware(request: NextRequest) {
  const token = request.cookies.get("session_token")?.value;
  const isProtectedPath = request.nextUrl.pathname.startsWith("/dashboard");

  if (isProtectedPath && !token) {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/dashboard/:path*", "/admin/:path*"],
};

Dynamic OpenGraph Metadata (generateMetadata)

Generate dynamic title tags, meta descriptions, and social preview images.

Docs
// app/blog/[slug]/page.tsx
import type { Metadata } from "next";

type Props = {
  params: Promise<{ slug: string }>;
};

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { slug } = await params;
  
  return {
    title: `${slug.replace(/-/g, " ")} | DevDossier`,
    description: `In-depth reference guide for ${slug}.`,
    openGraph: {
      title: `${slug} Guide | DevDossier`,
      images: [`/api/og?title=${encodeURIComponent(slug)}`],
    },
  };
}

Cite & Link This Resource

Backlink Magnet

Writing a blog post, GitHub README, or docs? Embed a backlink snippet or badge to cite this cheat sheet.

[Next.js 15+ App Router Cheat Sheet](https://devdossier.com/resources/nextjs-app-router-cheat-sheet) - Interactive Reference & Cheat Sheet via DevDossier
DevDossier Ecosystem20 Platforms

Find Us Everywhere

We publish, stream, and collaborate across every major developer & design platform. Follow along wherever you feel at home.

20+ Platforms
Global Presence
Developer First
Open Ecosystem
Daily Updates
Real-time Content
100% Free
Open Resources