Gu
Guillermo Rauch & Working Group@rauchgCore Maintainer VerifiedVercel Ecosystem

Specification Author & Maintainer • Verified via AgentRules Industrial Quality Gate

frontendcritical PriorityID: nextjs-15-app-router

Next.js 15 App Router & Server Actions Standard

Strict architecture guardrails for Next.js 15: strictly App Router (no pages/ bleed), async request APIs (cookies, headers, params), and secure Server Actions.

Prohibited Anti-Pattern: AI outputs legacy pages/ router, synchronous cookies(), or unvalidated server actions vulnerable to CSRF.

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Next.js 15 App Router & Server Actions Standard - Strict architecture guardrails for Next.js 15: strictly App Router (no pages/ bleed), async request APIs (cookies, headers, params), and secure Server Actions.
globs: app/**/*.{ts,tsx}, components/**/*.{ts,tsx}, actions/**/*.{ts,tsx}
alwaysApply: true
author: "Guillermo Rauch & Working Group (@rauchg)"
contributor_url: "https://github.com/rauchg"
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/nextjs-15-app-router"
---

# Next.js 15 App Router & Server Actions Standard

> **Severity**: CRITICAL | **Category**: frontend
> **Anti-Pattern Warning**: AI outputs legacy pages/ router, synchronous cookies(), or unvalidated server actions vulnerable to CSRF.

## System Constraints
You are a senior Next.js 15 architect. Never generate code using the deprecated pages/ router. In Next.js 15, cookies(), headers(), and route params are strictly asynchronous Promises. Server Actions must always sanitize and validate input using Zod or standard schemas before executing database queries.

## Strict Guidelines
- Never import from 'next/router'; only import navigation hooks from 'next/navigation'.
- In Next.js 15, cookies(), headers(), and params in layout/page props are asynchronous. Always await cookies() and await params.
- Server Actions ('use server') must treat all incoming parameters as untrusted user input; validate using Zod safeParse.
- Default to React Server Components (RSC). Only add 'use client' at leaf interactive components, never at page root layouts.
- Always use next/image with explicit width/height or fill attribute with sizes to prevent Cumulative Layout Shift (CLS).

## Bad vs Good Implementations
### Async Cookies & Params in Next.js 15

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: In Next.js 15, cookies(), headers(), and route params return Promises. Synchronous access triggers runtime warnings and breaks in production.
```typescript
// DEPRECATED Next.js 14 sync usage
import { cookies } from "next/headers";

export default function UserProfile({ params }: { params: { id: string } }) {
  const cookieStore = cookies(); // Error in Next.js 15: cookies() is async
  const token = cookieStore.get("session")?.value;
  return <div>User: {params.id}</div>; // params must be awaited in 15
}
```

#### Production Standard (Correct)
> **Standard**: Correctly awaits route params and cookies() as asynchronous Promises per the Next.js 15 specification.
```typescript
// Next.js 15 App Router Standard
import { cookies } from "next/headers";

interface PageProps {
  params: Promise<{ id: string }>;
}

export default async function UserProfile({ params }: PageProps) {
  const { id } = await params;
  const cookieStore = await cookies();
  const token = cookieStore.get("session")?.value;

  return <div>User: {id}</div>;
}
```

### Secure Server Actions with Zod Validation

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Unvalidated Server Action allows arbitrary input injection and lacks authentication verification.
```typescript
"use server";
import { db } from "@/lib/db";

export async function updateUser(formData: FormData) {
  const email = formData.get("email") as string;
  // Dangerous: No authentication check, no validation, direct SQL/ORM call
  await db.user.update({ where: { id: 1 }, data: { email } });
}
```

#### Production Standard (Correct)
> **Standard**: Enforces session authentication and strict Zod runtime schema validation on every Server Action invocation.
```typescript
"use server";
import { z } from "zod";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";

const UpdateUserSchema = z.object({
  email: z.string().email(),
});

export async function updateUser(formData: FormData) {
  const session = await auth();
  if (!session?.user?.id) throw new Error("Unauthorized");

  const parsed = UpdateUserSchema.safeParse({
    email: formData.get("email"),
  });
  if (!parsed.success) {
    return { success: false, errors: parsed.error.flatten().fieldErrors };
  }

  await db.user.update({
    where: { id: session.user.id },
    data: { email: parsed.data.email },
  });
  return { success: true };
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Next.js 15 App Router & Server Actions Standard

Next.js 15 introduces fundamental architectural shifts from previous major versions. Most notably, dynamic request headers, cookies, and route parameters are now strictly asynchronous Promises. Furthermore, the legacy `pages/` directory pattern has been superseded by the React Server Components (RSC) App Router model. Server Actions now require rigorous explicit runtime authorization and schema validation to prevent Server-Side Request Forgery (SSRF) and broken object-level authorization (BOLA).

Framework Paradigm Shift & Drift MechanicsLarge Language Models (LLMs) trained heavily on repositories written between 2020 and 2023 exhibit severe training distribution bias toward Next.js 12-14 paradigms. When prompted to generate routing, AI assistants instinctively import from 'next/router' instead of 'next/navigation', access `cookies()` synchronously, and assume route params are plain objects. In production, this causes immediate runtime UnhandledPromiseRejection errors and de-optimizes partial prerendering (PPR).
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
Synchronous Request API InvocationAI outputs `const token = cookies().get('session')` without `await`Critical
Next.js 15 throws runtime warnings in development and breaks dynamic rendering in production builds.
Strictly mandate `const cookieStore = await cookies()` and `const { slug } = await params` across all server components and route handlers.
Legacy Pages Router BleedAI creates `pages/api/...` endpoints or imports `useRouter` from 'next/router'High
Breaks streaming SSR, causes dual-bundle bloat, and creates conflicting routing trees in Next.js 15.
Enforce App Router route handlers (`app/api/**/route.ts`) and import `useRouter` strictly from 'next/navigation'.
Unauthenticated Server Action MutationsAI writes `"use server"; export async function deleteUser(id) { await db.delete(id); }` without auth checksCritical
Allows arbitrary users to execute mutations via publicly exposed POST endpoints without session verification.
Always verify session authentication via `auth()` and parse payloads with Zod schemas inside every Server Action.
Client Boundary Over-ScopingAI places 'use client' at page or layout roots to use simple state hooksMedium
Strips Server Component benefits, inflates client JavaScript bundle by up to 400%, and breaks streaming SSR.
Default to React Server Components (RSC); push 'use client' down to isolated leaf interactive widgets.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Never import from 'next/router'

Never import from 'next/router'; only import navigation hooks from 'next/navigation'.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

In Next.js 15, cookies(), headers(), and params in layout/page props are asynchronous. Always await cookies() and await params.

In Next.js 15, cookies(), headers(), and params in layout/page props are asynchronous. Always await cookies() and await params.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Server Actions ('use server') must treat all incoming parameters as untrusted user input

Server Actions ('use server') must treat all incoming parameters as untrusted user input; validate using Zod safeParse.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Default to React Server Components (RSC). Only add 'use client' at leaf interactive components, never at page root layouts.

Default to React Server Components (RSC). Only add 'use client' at leaf interactive components, never at page root layouts.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Always use next/image with explicit width/height or fill attribute with sizes to prevent Cumulative Layout Shift (CLS).

Always use next/image with explicit width/height or fill attribute with sizes to prevent Cumulative Layout Shift (CLS).

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why does Cursor AI keep generating Next.js pages/ router instead of App Router?

Pre-trained LLMs have seen millions of Next.js 12-14 codebases using the pages/ router. Without explicit system prompt constraints (.cursor/rules/*.mdc), the model defaults to the highest-probability statistical token distribution. Placing the Next.js 15 rule in your repository explicitly overrides this default bias.

Q:How do I fix 'cookies() is a Promise' error in Next.js 15?

In Next.js 15, `cookies()`, `headers()`, and route parameters (`params`) are asynchronous APIs. You must declare your Server Component or route handler as `async` and use `const cookieStore = await cookies();`.

Q:Are Next.js Server Actions automatically protected against CSRF?

Next.js validates the Host and Origin headers for Server Actions to guard against basic cross-site attacks. However, Server Actions act as public HTTP POST endpoints. You MUST still perform session validation (e.g. NextAuth/Auth.js) and input schema sanitization (Zod safeParse) inside every action.

Q:How does this rule file integrate with Cursor, Claude Code, and Windsurf?

In Cursor, drop it as `.cursor/rules/nextjs-15.mdc` with `globs: app/**/*.{ts,tsx},components/**/*.{ts,tsx}`. In Claude Code, append the directives to `CLAUDE.md`. In Windsurf, place it in `.windsurfrules`. In Codex/Cline, place it in `AGENTS.md`.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

Related FRONTEND Rules

View all rules →
frontend
119

SolidStart 1.0 Server Functions & Async Boundaries Production Standard

SolidStart 1.0 relies on the Vinxi bundler to split `server$` closures into independent HTTP POST RPC endpoints. Direct lexical closure over client signals within `server$` scopes or failure to demarcate async boundaries with `<Suspense>` causes silent serialization failures, client-bundle secret leaks, and SSR hydration mismatches. Enforcing strict parameter passing, runtime input validation, and Solid async primitives maintains security and fine-grained reactivity across network boundaries.

frontend
119

Astro 5 Actions & Content Layer Production Standard

Enforces strict type safety and architectural correctness for Astro 5 Server Actions and the zero-waterfall Content Layer API. Prevents runtime contract mismatches, hydration mismatches, and unhandled mutation exceptions across dynamic and prerendered boundaries. Failure to follow these patterns leads to silent data fetching waterfalls, build-time cache corruptions, and unhandled server action exceptions.

frontend
51

Nuxt 4 Nitro Server Engine & Shared Directory Production Standard

Nuxt 4 enforces strict boundary segregation between client UI in the app/ directory, backend endpoints in server/, and universal contracts in shared/. Violating cross-boundary isolation or maintaining module-scoped state in Nitro server handlers causes catastrophic cross-request data corruption and hydration mismatches under concurrent production traffic. Architects must enforce request-isolated H3 event contexts, universal serialization schemas, and strict path-alias boundaries.

1 Rule in Stack

Next.js