Next.js Rules for AI Agents in 2026: A Cursor / Claude / Copilot Context File
Knowledge
Cursor, Claude Code, GitHub Copilot — every AI coding agent your team uses ships with training data from a time when Next.js meant the Pages Router, getServerSideProps, and useEffect for everything. In 2026 that is the wrong default. App Router projects with React Server Components, Server Actions, and the new caching model are a different programming model, and agents generate broken or insecure code unless you tell them otherwise.
This article is the rules file we drop into every Next.js engagement we lead at Softescu. Copy it into .cursorrules, claude.md, or AGENTS.md, adjust the project-specific bits, and your agent stops hallucinating Pages Router patterns from 2022. If you want the broader picture on building AI features inside Next.js apps, our Next.js AI development guide covers the production patterns.
The format — agents.md, claude.md, .cursorrules
Three filenames, same idea: a markdown file at the project root that the agent reads on every prompt and uses as system context.
AGENTS.md— proposed open standard. Read by OpenAI Codex, Aider, and a growing list of agents..cursorrules— Cursor IDE's project rules file. Replaced by.cursor/rules/*.mdcin 2025; both still work.claude.mdorCLAUDE.md— read automatically by Claude Code at session start. Honoured globally (in~/.claude/) and per-project (in the working directory).
All three are plain markdown. The rules below are written so they work in any of them.
Rule 1 — Server Components are the default
Every component in app/ is a Server Component unless it explicitly opts out with 'use client'. Mark a file 'use client' only when the component uses one of:
- React state (
useState,useReducer) - React effects (
useEffect,useLayoutEffect) - Browser-only APIs (
window,localStorage,IntersectionObserver) - Event handlers attached in JSX (
onClick,onChange,onSubmit) - Third-party libraries that depend on any of the above
Anti-pattern: putting 'use client' on app/layout.tsx or any page that renders mostly static content. This forces the entire subtree into the client bundle and erases the framework's main performance advantage.
Rule 2 — Server Actions, not API Routes, for mutations
For form submits and any mutation triggered by user action inside the app, use a Server Action. Reach for an API Route (app/api/foo/route.ts) only when the endpoint must be callable from outside the app — by mobile clients, webhooks, third-party services, or scheduled jobs.
// app/contact/page.tsx
async function submit(formData: FormData) {
'use server'
await db.contactSubmissions.create({
email: formData.get('email'),
message: formData.get('message'),
})
revalidatePath('/contact')
}
export default function ContactPage() {
return <form action={submit}>…</form>
}
Anti-pattern: an agent generating a /api/contact/route.ts plus a client-side fetch('/api/contact', { method: 'POST' }) for a form that only this app submits to. Two files, an extra network hop, no progressive enhancement, no built-in CSRF protection.
Rule 3 — Fetch data in Server Components, never in useEffect
If a page needs data from the database or an external API, fetch it in the Server Component and pass it down as props. Do not generate a Client Component with useEffect(() => { fetch(…) }, []).
// app/posts/page.tsx — Server Component
import { db } from '@/server/db'
export default async function PostsPage() {
const posts = await db.posts.findMany()
return <PostList posts={posts} />
}
Anti-pattern: any useEffect that loads initial data. That is a 2021 pattern. The only legitimate use of useEffect in 2026 Next.js is integrating with imperative browser APIs — canvas, video, geolocation, WebSocket.
Rule 4 — Edge Runtime is opt-in
The default runtime is Node.js. Only set export const runtime = 'edge' when:
- The route is latency-sensitive and globally distributed (auth checks, geo-routing, A/B tests).
- The code uses only Edge-compatible APIs (Web Crypto,
fetch,Headers; no Nodefs, nocrypto.createHash, noBuffer). - The bundle is small (Edge has a ~1 MB compressed limit on most hosts).
Anti-pattern: an agent adding runtime = 'edge' to a route that imports Prisma, Drizzle's Node client, or any library that pulls in crypto/fs. The build will fail in production but pass in dev — exactly the failure mode you don't want.
Rule 5 — File structure
app/ # routes only — pages, layouts, route handlers
components/ # presentational React components, no data fetching
lib/ # framework-agnostic utilities, types, validators
server/ # server-only code: db client, auth, AI providers
public/ # static assets
server/ exists so the agent has a clear destination for code that must never reach the client bundle. Mark database connection files with import 'server-only' at the top — the build will fail loudly if a client component ever imports them.
Anti-pattern: agents creating pages/, services/, utils/, or hooks/ directories because their training data uses those conventions. Don't allow the parallel universe.
Rule 6 — URL state beats client state
If a piece of state would be reasonable to share by sending a URL — filters, pagination, sort order, the open tab on a settings page — store it in the URL via searchParams (Server Components) or useSearchParams (Client Components). It survives reloads, can be shared, and gets indexed by search.
Reach for Zustand, Jotai, or Redux only for true client-only state that cannot be in the URL: an open modal, a drag-in-progress, an unsaved form draft.
Anti-pattern: putting "current page = 3" in Zustand when ?page=3 does the same thing for free, with shareable links and back-button support.
Rule 7 — Streaming with Suspense for slow data
When a Server Component awaits something slow — an LLM call, a vector search, a third-party API — wrap it in <Suspense> and pass the awaiting child as the suspense boundary. The rest of the page renders immediately; the slow part streams in when ready.
export default function Page() {
return (
<>
<Header />
<Suspense fallback={<Skeleton />}>
<SlowRecommendations />
</Suspense>
</>
)
}
Anti-pattern: a single async page component that awaits everything sequentially before sending the first byte. Slow time-to-first-byte for no good reason.
Rule 8 — Cache explicitly, not by accident
Next.js 15 made caching opt-in. The agent should annotate every fetch and every route with an explicit caching intent:
fetch(url, { cache: 'force-cache' })— static, cache foreverfetch(url, { next: { revalidate: 60 } })— ISR, refresh every 60 sfetch(url, { cache: 'no-store' })— always fresh- Add
'use cache'to expensive Server Components that should be memoised - Add
export const dynamic = 'force-dynamic'on routes that must never be cached (auth-gated, personalised)
Anti-pattern: silently relying on the default. Different Next.js versions, different hosts, and different environments choose different defaults. Explicit annotations make the agent's intent reviewable.
The full context file you can copy-paste
Drop the block below into AGENTS.md, .cursorrules, or claude.md (or all three — they're identical). Adjust the stack lines at the bottom for your project, then commit it alongside the code.
# Next.js Rules for AI Agents
This is a Next.js 15+ App Router project. Follow these rules when generating
or editing code.
## Server Components by default
- Every component in `app/` is a Server Component.
- Mark a file `'use client'` only if it uses: useState, useEffect, browser
APIs, JSX event handlers, or libraries that need any of those.
- Never put `'use client'` on a layout or a mostly-static page.
## Server Actions for mutations
- Forms and in-app mutations use Server Actions (`'use server'`).
- API Routes (`app/api/*/route.ts`) are only for external callers: mobile
clients, webhooks, scheduled jobs.
## Data fetching
- Fetch in Server Components, pass data down as props.
- Do not use `useEffect` to load initial data.
- `useEffect` is only for imperative browser APIs (canvas, video, etc).
## Edge Runtime
- Default is Node.js. Do not set `runtime = 'edge'` unless explicitly asked.
- If switching to edge: only Web APIs, no Node `fs`/`crypto`/`Buffer`, bundle
under ~1 MB.
## File structure
- `app/` — routes only (pages, layouts, route handlers)
- `components/` — presentational React, no data fetching
- `lib/` — framework-agnostic utilities, types, validators
- `server/` — server-only code; add `import 'server-only'` at the top
- `public/` — static assets
- Do not create `pages/`, `services/`, `utils/`, or `hooks/` directories.
## State
- URL state (`searchParams`, `useSearchParams`) beats client state.
- Use Zustand/Jotai/Redux only for state that cannot reasonably live in
the URL (open modals, drag state, unsaved drafts).
## Streaming
- Wrap slow Server Components in `<Suspense fallback={…}>`.
- Do not await everything in one async page component.
## Caching
- Annotate every fetch: `cache: 'force-cache' | 'no-store'` or `next.revalidate`.
- Use `'use cache'` on expensive Server Components.
- Use `export const dynamic = 'force-dynamic'` on auth-gated / personalised
routes.
## Project stack (edit per project)
- TypeScript strict mode
- Tailwind CSS + shadcn/ui
- Drizzle ORM + Postgres
- Auth.js (NextAuth) for authentication
- Vercel AI SDK for LLM calls (server-side only)
- Zod for runtime validation
How we use this at Softescu
We maintain a base version of this file across our Next.js client engagements and version it alongside the code. Two project conventions we always add on top:
- A
server/ai/directory for LLM provider clients, prompts, and rate limits — referenced from Server Actions only, never from client components. - A note in the rules file about which logging or analytics tags the agent should add when generating new pages — we run OpenPanel across our work, and the agent reliably adds the correct data attributes if the rules file mentions them.
The rules file is not a one-time setup. We treat it like a CI configuration: when an agent generates code that doesn't match a project convention, we either fix the agent's behaviour through a new rule, or accept the convention has drifted and update the codebase. Either way, the file is the source of truth.
If your team is starting a Next.js project and wants help establishing an AI-agent-friendly setup — rules files, structure, RAG patterns for AI features inside the app itself — get in touch.