Skip to main content

May 2026 · Workflow · ~10 min read

The Production-Ready .cursorrules Template for Next.js App Router Teams

By Safdar Ali — frontend engineer, Bengaluru

My Cursor + Claude workflow post covers how I prompt and review. This one is what the model sees before every Agent run: the context file. Most teams write rules that make AI generate components faster. Fewer write rules that block env leaks, wrong client boundaries, or TypeScript shortcuts that fail CI.

I keep this in .cursor/rules/nextjs-app-router.mdc (Cursor's current format) on every Next.js 15 repo. Copy it, trim project-specific paths, commit it. Agentic coding only scales when non-functional requirements are as explicit as "use Tailwind."

Why most context files fail in production

  • They describe stack ("we use Next.js") but not boundaries (Server vs Client)
  • No rule against process.env.SECRET in client files
  • No instruction to run npm run build before declaring done
  • Generic "write clean code" — models ignore it under time pressure
  • Missing reference files — Agent invents a new folder layout every ticket

Research on AI context files matches what I see in review: functional rules get followed; security and performance rules get skipped unless they are concrete and testable.

The full template (copy-paste)

Below is my literal file — ~120 lines. Replace REFERENCE_LAYOUT=app/blog/rsc-vs-client-components/page.tsx with your best article or page component.

---
description: Next.js 15 App Router production rules for Agent and Chat
globs: app/**/*.{tsx,ts,jsx,js}, components/**/*, lib/**/*
alwaysApply: true
---

# Role
You are a senior frontend engineer on a Next.js 15 + React 19 + TypeScript (strict) codebase.
Optimize for: correct RSC boundaries, minimal client JS, accessibility, SEO metadata, and passing `npm run build`.

# Stack (do not substitute)
- Next.js App Router only — no Pages Router patterns
- TypeScript strict — no `any`, no `@ts-ignore` without comment
- Tailwind for styling — match existing class patterns
- Data: Server Components + fetch/cache tags OR Server Actions — no new REST routes unless asked

# Server vs Client (mandatory)
- Default: Server Component — no "use client" unless interactivity, browser APIs, or hooks required
- Never import server-only modules into client components (db, fs, raw env secrets)
- Never put "use client" on layouts that only wrap children unless required
- Split: server shell fetches data; client island is the smallest interactive leaf
- Reference pattern: app/blog/rsc-vs-client-components/page.tsx (structure, metadata, prose classes)

# Streaming & Suspense
- Wrap slow server fetches in <Suspense> with skeleton matching final layout dimensions (prevent CLS)
- Do not await unrelated data serially in one page — parallelize with Promise.all
- loading.tsx must mirror final layout geometry

# Environment & secrets
- Client code: only NEXT_PUBLIC_* env vars
- Never log or stringify process.env in client bundles
- Server secrets only in Server Components, Route Handlers, or Server Actions marked "use server"
- If unsure whether a var is public, treat as server-only

# TypeScript
- Props: explicit interfaces, export types from colocated types.ts when shared
- Server Actions: Zod (or existing validator) at top of action — return typed ActionResult
- Prefer `satisfies` over assertions

# SEO & metadata
- Every new route: export metadata or generateMetadata with title, description, canonical
- One h1 per page; heading hierarchy must not skip levels
- Images: next/image with width/height or fill + sizes

# Performance (non-optional)
- No barrel imports that pull entire libraries into client bundles
- dynamic() for heavy client charts/editors with ssr: false inside reserved-height containers
- Before removing useMemo/useCallback: note "verify in React Profiler — Compiler may not cover module refs"

# Security
- No dangerouslySetInnerHTML without explicit approval in ticket
- Sanitize user HTML if required
- Server Actions: validate auth inside action, not only in UI

# Agent workflow
1. Analyze pass: list files to touch, risks, RSC boundary plan — no edits
2. Implement pass: minimal diff, match conventions, no drive-by refactors
3. Run: npm run build — fix all errors before finishing
4. Summarize: what changed, what to manually test (mobile, dark mode, SEO)

# Forbidden without explicit ask
- New state management libraries
- Converting Server Components to client "for simplicity"
- Adding API routes when Server Actions suffice
- Changing tailwind.config, next.config, or CI files

# Project paths (customize)
- Blog pattern: app/blog/[slug]/page.tsx
- UI classes: lib/ui-classes.js
- Data: data/*.js — keep fetch logic out of client components

Claude / Cursor custom instructions

For cursor ai claudecustom prompt configuration, I mirror the same bullets in Cursor Settings → Rules for AI (user-level) but keep repo-specific paths only in .cursor/rules. User rules say "always respect project .cursor/rules"; project rules say "reference rsc-vs-client-components page." That split stops personal preferences from leaking into client repos.

Agent mode prompt I prepend

Follow .cursor/rules/nextjs-app-router.mdc exactly.
Task: [one paragraph scope]
Done when: build passes, no new client boundaries without justification, dark mode unchanged.

Rule in action: forcing RSC boundaries

Without rules, Agent often produces this:

"use client";
import { getPosts } from "@/lib/db";

export default function BlogPage() {
  const [posts, setPosts] = useState([]);
  useEffect(() => { getPosts().then(setPosts); }, []);
  // ...
}

With rules + reference file, the same ticket yields server fetch + client filter island — matching how I document RSC splits.

Rule in action: blocking env leaks

I caught Agent adding console.log(process.env) in a client hook for debugging. The rule line "Never log process.env in client bundles" plus globs on components/** reduced repeats. For how to configure cursor for typescript, the strict-mode bullets matter more than model choice — Sonnet still emits any without guardrails.

TypeScript enforcement snippet

Add to rules if your team uses Server Actions heavily:

# Server Actions shape
type ActionResult<T> =
  | { ok: true; data: T }
  | { ok: false; error: string };

Every action returns ActionResult — never throw to client for validation errors.

Agentic coding workflows that respect rules

  1. Ticket → analyze-only Agent — outputs file list + boundary diagram in comments
  2. Implement Agent — must cite which rule applied for each new "use client"
  3. Human review — check env, metadata, CLS skeletons (rules mention them; humans verify)
  4. Build in CI — rules are worthless if merge does not require green build

Compare tools: GitHub Copilot vs Cursor. Broader AI coding context: how AI changed React coding.

Closing

The best cursorrules for nextjs are boring: explicit Server/Client law, env boundaries, build gate, reference files. Agentic coding workflows only beat copy-paste when the model cannot pretend performance and security are optional. Drop this file in your repo today; tighten paths tomorrow.

If this helped you

I publish free tutorials and write-ups like this in my spare time — no paywall on the guides. If it saved you an afternoon of trial and error, you can support the work:

More guides on safdarali.in — same author, production-focused.

"Talk is cheap. Show me the code."