Blog/Tutorial
Best Practices

How to Write Cursor Rules That Actually Work (And Why They Fail)

If you are using Cursor for vibe coding, you know the pain of the AI hallucinating an outdated library or ignoring your team's styling conventions. The standard fix is to write a `.cursorrules` file. But if you do it wrong, you will just confuse the model even more. Here is how to write rules that work—and the hidden limit you will eventually hit.

April 6, 2026·7 min read·Jason

A `.cursorrules` file is essentially a system prompt that gets injected into every request you make to the Cursor AI. It tells the LLM how to behave, what tech stack you are using, and what patterns to avoid.

When written well, cursor rules can drastically reduce the amount of time you spend correcting the AI. When written poorly, they waste context window tokens and lead to bizarre hallucinations.

The 3 Golden Rules of Cursor Rules

1. Be Explicit About "Never"

LLMs are people-pleasers. If you say "prefer using X," the model might still use Y if it saw Y in a file it just read. You need to use strong, definitive language for things that are non-negotiable.

Bad Rule
Try to use Tailwind for styling instead of CSS files.
Good Rule
NEVER write raw CSS. ALWAYS use Tailwind utility classes. If a complex animation is needed, use standard Tailwind arbitrary values.

2. Scope Your Rules Using .mdc Files

Dumping 500 lines of instructions into a single global `.cursorrules` file is a terrible idea. It eats up your token limit on every prompt, even when the rules aren't relevant.

Instead, use the newer `.cursor/rules/` directory with `.mdc` (Markdown Component) files. This allows Cursor to selectively load rules only when specific files are open.

---
description: Database schema and Prisma rules
globs: prisma/schema.prisma, src/db/**/*.ts
---
# Database Rules
1. Never use raw SQL queries, always use the Prisma client.
2. All dates must be stored in UTC.
3. Soft delete records using the `deletedAt` timestamp instead of dropping rows.

3. Provide Concrete Examples

Models learn best from few-shot prompting. If you have a specific architectural pattern, do not just describe it—show it.

# API Route Pattern
Always wrap API route handlers in our custom `withAuth` middleware.

GOOD:
export const GET = withAuth(async (req, session) => {
  return NextResponse.json({ data: [] });
});

BAD:
export async function GET(req: Request) {
  // Do not do manual auth checks here
}

The Hidden Problem: Why Rules Break Down

If you follow the best practices above, your Cursor experience will improve significantly. But eventually, you will hit a wall.

Static rules cannot handle dynamic project state.

A `.cursorrules` file is static. It is great for establishing your tech stack (e.g., "Use Next.js App Router"). But it is terrible at tracking the actual progress of your project.

  • It doesn't know that you just decided to deprecate the `UserCard` component yesterday.
  • It doesn't know that you are currently in the middle of a database migration and half the tables are broken.
  • It doesn't remember the nuanced discussion you had with the agent two hours ago about why a specific API endpoint keeps timing out.

The Context Bloat Trap

When developers realize the AI is forgetting dynamic state, they start manually editing their `.cursorrules` file every day to add "current project status" notes. This causes the file to bloat massively. The LLM gets overwhelmed by the wall of text, token costs skyrocket, and the agent starts hallucinating because it cannot separate core rules from temporary notes.

The Evolution: From Static Rules to Persistent Memory

To fix this, you need to separate your static conventions from your dynamic memory.

Keep your `.cursorrules` for the static stuff: "Use TypeScript," "Use Tailwind," "No semicolons."

For everything else, you need an active memory system. This is where the Model Context Protocol (MCP) comes in. By connecting an MCP memory server like Memstate AI to Cursor, you give the agent a read/write brain.

Instead of manually updating a rules file, the agent can actively save facts as you work:

"Hey Memstate, save a note that the /api/webhook endpoint is temporarily returning 500s due to a Stripe issue, so we should mock the response for now."

Tomorrow, when you ask Cursor to work on the webhook, it will query Memstate, retrieve that exact fact, and know exactly how to proceed—without you having to explain it again, and without cluttering up your static rules file.

Level Up Your Vibe Coding

Writing good Cursor rules is the first step to mastering AI-assisted development. The second step is realizing that rules are just the beginning. By combining strict `.mdc` rules for syntax with a persistent MCP memory layer for project state, you can finally stop repeating yourself and just code.

Upgrade from Rules to Memory

Stop manually editing your rules file. Give Cursor persistent, auto-updating memory with Memstate MCP.