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).
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 Mode | AI Symptom (The Anti-Pattern) | Severity | Production Impact & Remedy |
|---|---|---|---|
| Synchronous Request API Invocation | AI 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 Bleed | AI 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 Mutations | AI writes `"use server"; export async function deleteUser(id) { await db.delete(id); }` without auth checks | Critical | 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-Scoping | AI places 'use client' at page or layout roots to use simple state hooks | Medium | 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. |
Step-by-Step Production Directives
Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:
Never import from 'next/router'
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.
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
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.
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).
Always use next/image with explicit width/height or fill attribute with sizes to prevent Cumulative Layout Shift (CLS).
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`.
