How to Set Up Cursor Rules for Next.js Projects
If you've been using Cursor on a Next.js project for more than a week, you've probably caught it doing something like this: generating a getServerSideProps function in an App Router project, reaching for useEffect to fetch data that should live in a Server Component, or scattering "use client" directives across files that don't need them.
These aren't random mistakes. They happen because Cursor's default context is general React knowledge, and Next.js, especially the App Router, has specific patterns that conflict with how most React tutorials were written. A .cursorrules file fixes this by giving Cursor explicit instructions at the start of every session.
This is a setup guide. By the end you'll have a working rules file and a clear idea of what to put in it.
What .cursorrules Actually Does
When you open a project in Cursor, it looks for a .cursorrules file in the root directory and prepends its contents to the system prompt for every AI interaction in that project. It's a persistent briefing that runs before every chat message and inline edit.
Rules you write there apply automatically. You don't have to say "remember we're using the App Router" at the start of each conversation. Cursor already knows.
The file is plain text. No special syntax, no configuration format. Write it like you're onboarding a developer who's smart but unfamiliar with your codebase.
Where to Put It
Root of your project, same level as package.json:
my-nextjs-app/
├── .cursorrules ← here
├── package.json
├── next.config.ts
├── app/
└── components/
Cursor picks it up automatically. No configuration required.
The Rules That Actually Matter for Next.js
1. Lock it to the App Router
The single most important rule. Without it, Cursor will mix in Pages Router patterns constantly.
This project uses Next.js 14+ with the App Router.
Do not use the Pages Router. Do not generate getServerSideProps,
getStaticProps, getStaticPaths, or _app.tsx. All routing is
file-based under the /app directory.
2. Server Components are the default
Cursor tends to add "use client" defensively, even when it's not needed. This bloats the client bundle and defeats the purpose of Server Components.
React Server Components are the default. Do not add "use client"
unless the component uses browser APIs, event handlers, useState,
useEffect, or other client-only hooks. If in doubt, keep it a
Server Component.
A useful mental model to include: if it fetches data or renders static markup, it's a Server Component. If it handles interaction, it's a Client Component.
3. Data fetching belongs in Server Components
This is where most AI assistants go wrong. They reach for useEffect and useState because that's how most React examples are written. In the App Router, data fetching lives in the component itself, on the server.
Fetch data directly in Server Components using async/await.
Do not use useEffect or useState for data fetching. Do not create
API routes just to proxy data to client components. Fetch from
the data source directly in the Server Component.
Example:
async function ProductPage({ params }) {
const product = await getProduct(params.id)
return <ProductView product={product} />
}
4. Correct file conventions
Cursor sometimes generates pages/ files or gets Next.js filenames wrong. Be explicit:
Next.js App Router file conventions:
- app/page.tsx: route UI
- app/layout.tsx: shared layout
- app/loading.tsx: loading state
- app/error.tsx: error boundary (must be "use client")
- app/not-found.tsx: 404 UI
- app/api/.../route.ts: API route handlers (not /pages/api/)
Do not create files under /pages/. API routes go in app/api/ as
route.ts files exporting GET, POST, etc.
5. TypeScript strictness
If you're using TypeScript, tell Cursor how strict you want it:
Use TypeScript for all new files. Do not use `any`. Define prop
types with interfaces, not inline type literals. Prefer explicit
return types on components over relying on inference.
A Complete Starting File
Here's a full .cursorrules file you can drop in and adjust:
# Next.js App Router Project
## Framework
- Next.js 14+ with App Router
- TypeScript, strict mode
- Tailwind CSS for styling
## Routing
- All routes live under /app
- Do not use Pages Router patterns (no getServerSideProps, getStaticProps, _app.tsx)
- File conventions: page.tsx, layout.tsx, loading.tsx, error.tsx, route.ts
## Components
- React Server Components are the default: do not add "use client" unless required
- Use "use client" only for: event handlers, browser APIs, useState, useEffect, useRef
- Keep Client Components small and push them to the leaves of the component tree
## Data Fetching
- Fetch data in Server Components using async/await directly
- Do not use useEffect or useState for data fetching
- API routes go in app/api/ as route.ts files, not pages/api/
- Cache behavior: use Next.js fetch options (cache: 'no-store', next: { revalidate: n })
## TypeScript
- No `any` types
- Props defined as interfaces
- Async server components: async function Component(): Promise<JSX.Element>
## File Organization
- /app: routes and layouts
- /components: shared UI components
- /lib: utilities, data fetching helpers, types
- /public: static assets
## Do Not
- Do not mix Server and Client Component patterns in the same file
- Do not fetch data in Client Components when a Server Component can do it
- Do not use the Image component with unoptimized={true} unless specifically required
- Do not generate placeholder data. Ask what the real data source is
Verifying It Works
After creating the file, open Cursor and ask it to "create a page that fetches a list of users from our API." If the output is an async Server Component making a direct fetch call, the rules are working. If it reaches for useEffect, check that the file is in the right location and restart Cursor.
You can also open Cursor chat and ask "what are my project rules?" and it'll summarize what it read from .cursorrules.
Where to Go From Here
A rules file is a living document. When you catch Cursor making the same mistake twice, add a rule. When your stack changes, update it.
The rules above cover the biggest failure modes for Next.js App Router projects. Every codebase also has its own patterns: your auth setup, your data layer, your component conventions. The more specific you make the file, the more consistent Cursor becomes.
For a broader look at how repository structure complements rule files, see Structuring Repositories for AI Coding Tools.
If you want a production-grade starting point with rules across multiple stacks, that's what ShipKit is.