Prompting Cursor well is less about phrasing and more about pointing. Cursor is an IDE — a fork of VS Code with AI woven into the editing surface — and its best prompts leverage its context primitives: @file and @folder for code, @docs and @web for references, a .cursorrules file for project ground rules, and Composer for multi-file changes. Prompts that name context explicitly converge fast. Prompts that ask the model to guess waste turns. This guide covers the mechanics.
What Cursor Is
Cursor is an IDE-native AI coding environment built as a fork of VS Code. The usual editor is there — file tree, tabs, terminal, extensions — alongside AI surfaces wired into the editing flow: an inline prompt for edits at the cursor, a side chat for questions with project context, and a Composer panel for changes that span files.
The shift is where the prompt lives. In chat, the prompt is the whole conversation. In Cursor, it is one part of a larger context: open files, mentioned files, the project rules file, and any docs or web pages you pull in. The prompt says what you want; the context primitives say what to look at.
For broader context, see the pillar: The Complete Guide to Prompting AI Coding Agents. For the category definition, see agentic AI.
How Cursor Prompting Differs From Chat AI and From Claude Code
Cursor sits between a chat model and a terminal-native agent. It has more autonomy than chat — it edits files directly, reads the project, and keeps project rules in memory — and less than a terminal agent, because it stays in the editor with the developer in the loop.
| Dimension | Chat AI | Cursor | Claude Code |
|---|---|---|---|
| Surface | Web page | IDE (VS Code fork) | Terminal inside repo |
| Context model | Paste snippets | @file, @folder, @docs, @web, .cursorrules | CLAUDE.md, tool-scoped reads |
| File edits | Copy-paste from reply | Direct edits in the editor | Direct edits via Edit/Write tools |
| Multi-file work | Manual stitching | Composer mode | Sequential tool calls |
| Shell access | None | Terminal integration, with confirmations | Bash tool, permission-gated |
| Autonomy shape | Reactive | Developer-in-the-loop edits | Longer autonomous runs |
| Best-fit prompt | A question | A targeted ask with @ context | A work-order spec |
The practical consequence for prompting: in chat you carry the whole context in the prompt; in Cursor, you carry most of it in @ mentions and .cursorrules, and you keep the prompt itself tight. A Cursor prompt that reads like a chat prompt — "can you figure out why the login flow is flaky?" — leaves the model guessing which files to open. The same ask with @file references converges immediately. For the terminal-native sibling, see the Claude Code prompting guide; for an IDE-native sibling, see the Windsurf AI prompting guide.
.cursorrules — The Project-Level Instruction File
.cursorrules is a file in your project root that carries project-wide instructions across every Cursor session. It is the Cursor analogue of CLAUDE.md — a single place to encode stack, conventions, scripts, and do/don't rules so you do not repeat them every prompt.
What tends to belong in .cursorrules:
- Stack — language, framework, version. Testing and build commands.
- Conventions — style rules, immutability, file-size norms, naming.
- Architecture notes — directories and what lives where, allowed import directions.
- Do / don't rules — files the AI should not edit without asking, dependencies to avoid, patterns the team decided against.
- Verification — typecheck, test, and lint commands, and what "done" looks like.
Compared to CLAUDE.md, the shape is similar: a plain-text instructions file in the project root that the tool reads automatically. The differences are mechanical, not conceptual — both solve the same problem, which is that the AI should know your project before you start typing.
A plausible .cursorrules snippet:
# Project: Acme Web
Stack:
- TypeScript (strict), React 19, Next.js 15 App Router
- Tailwind CSS, Supabase (Postgres + RLS)
- Tests: Jest + React Testing Library. Run `npm test`.
- Typecheck: `npm run typecheck`. Lint: `npm run lint`.
Conventions:
- Functional components only. No class components.
- Immutable data. Never mutate props or shared state.
- Files under ~400 lines. Functions under ~50 lines.
- Validate external input with Zod at route boundaries.
- Prefer server components; mark client components explicitly.
Directory rules:
- `app/` — routes. Server components by default.
- `lib/` — pure utilities. No network calls here.
- `lib/supabase/` — DB access. Do not import these from client code.
- `components/` — UI. Keep side-effect-free where possible.
Do not:
- Edit `supabase/migrations/*` without being asked.
- Add new dependencies without surfacing the choice first.
- Silently swallow errors. Surface them or log with context.
When done:
- Run `npm run typecheck && npm run lint && npm test`.
- Summarize the diff and the commands you ran.
Treat the above as an example, not an "official" template — shape fits the repo. Every line removes a decision the AI would otherwise guess at.
@ Context Mentions — Composing Context in the Prompt
Cursor lets you reference concrete context inside a prompt using @ mentions:
@file— a specific file. Use when you know which file matters.@folder— a folder's contents. Use when the scope is a module and you want the AI aware of its shape.@docs— documentation the tool has configured. Use for API reference or framework docs not in your repo.@web— web content. Use to pull in a URL or look up current information the model may not have.@git— git state (branches, diffs, commits). Use when the task is framed against a recent change.
Cursor also supports referencing project symbols and past chats; the exact menu evolves, so check the current docs.
The leverage of @ mentions is that they move context out of the prose and into structured pointers the AI can resolve directly. Instead of pasting a file, you mention it and the AI reads the current contents. Instead of describing an API, you point to the docs. A Cursor prompt that composes context well:
I want to add rate limiting to our signup endpoint.
Context:
@file app/api/signup/route.ts (the endpoint to change)
@file lib/rate-limit.ts (existing rate limiter pattern)
@file app/api/login/route.ts (reference — already rate limited)
@docs (our rate limit strategy doc, if indexed)
Ask:
Apply the same rate-limit wrapper used in the login route to the signup
route. Use an identifier based on IP + email. Keep behavior identical
otherwise.
Out of scope:
Do not change the schema. Do not touch any other routes. Do not install
new packages — use the existing rate limiter.
Acceptance:
- The signup route returns 429 when rate limited.
- No existing tests break (`npm test`).
- Only `app/api/signup/route.ts` and its test file are changed.
Every part of the prompt is either a pointer to concrete context or an explicit constraint. The AI does not guess which files to read, which pattern to copy, or what finished looks like. For the discipline behind this shape, see spec-driven AI coding. For the category, see the tool use glossary entry.
Composer Mode — Multi-File Edits
Composer is Cursor's surface for multi-file changes. Where inline editing touches the code at your cursor and chat answers questions, Composer describes a change that spans several files and carries it out. It is the closest Cursor gets to an agent: you give it a goal, it plans edits, and you review.
Good Composer prompts look like work orders — clear goal, files in scope (via @file or @folder), explicit out-of-scope, and a checkable "done." Composer earns its keep on changes that are fiddly across files: renaming a concept, migrating a pattern, extracting a helper, scaffolding a feature that spans routes, components, and tests. Composer has also been extended with agent-style execution where it can run commands as part of the change — the naming and specifics have evolved across Cursor versions, so check the current docs for which mode does what. The prompting principle is stable: give Composer a scoped, checkable ask with explicit context; do not ask it to "clean up the codebase."
Skip Composer for single-file fixes (inline edit is faster), for open-ended questions (use chat), and for sweeping rewrites (break them into phases).
Cmd-K vs. Chat vs. Composer — Choosing the Right Surface
Cursor gives you three main surfaces, and picking the right one matters. Using Composer for a one-line fix is overkill; using chat for a ten-file refactor means hand-stitching every edit.
- Inline edit — changes at the cursor. Rename, extract, fix the types on a function. Fast, local, easy to revert. The workhorse.
- Chat — questions and exploration. "Why does this fail?", "Is there a pattern for X in this repo?" Chat reads the project but does not edit it.
- Composer — multi-file execution. A specific change spanning files, with scope and acceptance.
Rough rule: single file and under ~30 lines, use inline. Asking a question, use chat. "I want these four files in a specific new shape," use Composer. Escalate only when the smaller surface hits its edge.
A Good Cursor Task Prompt
The pattern that works across Cursor surfaces: tight ask, explicit @ context, explicit scope, verifiable acceptance. This example is for Composer; the structure transfers.
GOAL
Migrate the `legacy-fetch` helper calls in `app/(dashboard)/` to use
the new `apiClient` from `lib/api/client.ts`.
CONTEXT
@file lib/api/client.ts (the new client)
@file lib/legacy-fetch.ts (the old helper, for reference only)
@folder app/(dashboard) (routes that need migrating)
BEHAVIOR
- Replace calls to `legacyFetch(...)` with `apiClient.request(...)`.
- Preserve error handling. Transient errors keep retrying under the new
client's defaults.
- Do not delete `lib/legacy-fetch.ts` — other modules still use it.
OUT OF SCOPE
- Any file outside `app/(dashboard)/`.
- Changes to `lib/api/client.ts` itself.
- New dependencies.
ACCEPTANCE
1. `grep -r "legacyFetch" app/(dashboard)` returns no matches.
2. `npm run typecheck` passes.
3. `npm test app/(dashboard)` passes.
4. `git diff --name-only` shows only files under `app/(dashboard)/`.
CLOSING STEP
Summarize the diff, paste the command outputs, and stop. Do not commit.
Every section closes a gap the AI would otherwise guess at. For the full pattern across tools, see the pillar guide.
Common Anti-Patterns
- No
.cursorrules, so every prompt re-explains the project. Conventions are implicit and the AI drifts. Fix: write a short.cursorruleson day one; update it when rules change. - Prose context instead of
@mentions. Describing a file in English when you could@fileit wastes tokens and risks a stale mental model. Fix: mention the file; let the AI read current contents. - Using chat for multi-file edits. You end up pasting code blocks by hand and the AI drifts between files. Fix: promote the ask to Composer with scoped
@file/@foldermentions. - Using Composer for trivial fixes. A multi-file surface burned on a one-line change. Fix: use inline edit.
- Vague acceptance. "Make this work" is not checkable. Fix: list commands or greps the AI can run to verify; make the stop condition explicit.
- Trusting the edit without reading the diff. The AI can touch unexpected files or leave broken imports. Fix: diff-review every Composer run; re-run tests yourself.
FAQ
What is the difference between .cursorrules and CLAUDE.md?
Both are project-level instruction files — plain-text instructions in the project root that the tool reads automatically. .cursorrules is Cursor's; CLAUDE.md is Claude Code's. Contents look similar (stack, conventions, do/don't rules, verification), and both serve the same purpose: teach the AI the project once so you do not repeat yourself every prompt. Using both in the same repo is fine — each tool reads its own.
Should I paste file contents into the prompt, or use @file?
Use @file. Pasting is fine for a one-off scratch prompt, but @file gives the AI current contents, keeps your prompt short, and lets you reference several files without bloat. The only time pasting wins is when you want the AI to work against a specific historical version that differs from what is on disk.
When should I use Composer versus inline edit?
Inline edit for changes at your cursor that stay in one file. Composer for changes that span files or need a plan before execution. If you catch yourself tabbing between files to apply the same inline edit, switch to Composer with the files listed.
How do I keep Cursor from editing files I did not want changed?
Three layers. In .cursorrules, mark off-limits directories. In the prompt, name the files or folders in scope and out of scope. In the acceptance criteria, ask the AI to report git diff --name-only and stop if any file outside scope was modified. Layered constraints beat any single one.
Can Cursor run shell commands?
Yes, through its terminal and agent-style execution surfaces, typically with a confirmation step. Let it run reads, tests, typecheck, and lint. Keep it confirming on installs, destructive operations, and anything that touches branches outside your current feature. The pillar guide has the longer tool-policy discussion.