Cursor Rules for Next.js: A Working .mdc Setup You Can Copy

If Cursor keeps writing pages/ router code in your App Router project, adding "use client" to everything, or fetching data in useEffect when a Server Component would do, it isn't being stubborn. It just doesn't know your project's rules. Cursor rules are how you tell it.

This guide shows a setup that works for a typical Next.js App Router project, with starter rules you can copy.

How Cursor rules work (the short version)

Project rules live in .cursor/rules/ as .mdc files. Each file is Markdown with a small header that tells Cursor when to use it:

---
description: Conventions for Next.js App Router pages and layouts
globs: app/**/*.tsx
alwaysApply: false
---

A folder layout that stays manageable

.cursor/rules/
  00-project.mdc        # alwaysApply: stack, versions, hard rules
  app-router.mdc        # globs: app/**
  server-actions.mdc    # globs: app/**/actions.ts, **/*.action.ts
  components.mdc        # globs: components/**
  data-fetching.mdc     # description-triggered
  testing.mdc           # globs: **/*.test.ts*

One topic per file. Small, specific rules beat one giant file that the model half-reads.

Starter rules you can paste

00-project.mdc (always on)

---
description: Core project facts
alwaysApply: true
---
- Next.js App Router (app/ directory). Never create files under pages/.
- TypeScript strict mode. No `any` unless commented with a reason.
- Tailwind for styling. No new CSS files without asking.
- Package manager: pnpm. Don't suggest npm or yarn commands.
- Before adding a dependency, say why and ask first.

Edit the specifics (pnpm, Tailwind) to match your project. The point is to state facts the model would otherwise guess.

app-router.mdc

---
description: App Router conventions
globs: app/**/*.tsx
alwaysApply: false
---
- Components are Server Components by default. Add "use client" only when the
  file uses state, effects, browser APIs, or event handlers.
- Push "use client" down to the smallest leaf component that needs it.
- Fetch data in Server Components with async/await, not in useEffect.
- Use layout.tsx for shared UI, loading.tsx for suspense states,
  error.tsx for error boundaries, not-found.tsx for 404s.
- Export `metadata` or `generateMetadata` from pages for titles/descriptions.
- Use next/link for internal links and next/image for images.

server-actions.mdc

---
description: Server Actions rules
globs: app/**/actions.ts
alwaysApply: false
---
- Mark files with "use server" at the top.
- Validate every input (e.g. with zod) before touching the database.
- Check auth inside the action. Never trust that the UI hid the button.
- Call revalidatePath or revalidateTag after mutations that change shown data.
- Return typed results ({ ok: true, data } | { ok: false, error }); don't throw
  raw errors to the client.

data-fetching.mdc

---
description: Use when writing code that fetches or caches data
alwaysApply: false
---
- Prefer fetching in Server Components close to where data is used.
- Be explicit about caching on fetch calls; don't rely on defaults, because
  caching defaults have changed between Next.js versions.
- Never expose secrets to client components. Server-only env vars stay
  without the NEXT_PUBLIC_ prefix.

The caching note matters: Next.js has changed its default fetch caching behavior across major versions (Next.js 15 stopped caching fetch by default), and models trained on older code often assume the old default.

Habits that make rules actually stick

Want the full set?

The rules above are a starting point. Our Next.js Cursor Rules Pack covers the rest of a real App Router project: auth, forms, testing, metadata and SEO, and more. If you want to try the format first, grab the free sample.

Last reviewed: October 2026.

Related: nextjs cursor rules · free sample