Rules and Project Context
Rules and Project Context
One of the most powerful — and most underused — features of Cursor is the ability to give the AI persistent, project-level instructions. Instead of repeating your tech stack, naming conventions, and architectural patterns in every prompt, you write them once and Cursor applies them automatically.
The problem without rules
Without rules, every Composer or Chat session starts from zero. The AI does not know:
- Whether you use TypeScript strict mode
- Whether you prefer functional components or class components
- What your error handling pattern looks like
- Which libraries you use for testing, HTTP calls, or state management
- Whether
anyis forbidden or acceptable
So it guesses. Sometimes it guesses right. Often it generates code that technically works but does not fit your codebase and requires editing.
The .cursorrules file
Create a file called .cursorrules in the root of your project. Cursor reads it automatically and includes it in every Chat and Composer context. It is plain text — write it like a memo to a new developer joining your team.
Example .cursorrules for a TypeScript React project
code# Project: Froquiz Frontend ## Tech stack - Next.js 14 with App Router - TypeScript (strict mode, no `any`) - Tailwind CSS for styling - Zustand for global state - React Query for server state and data fetching - Vitest + React Testing Library for tests - ESLint + Prettier (auto-formatted on save) ## Code style - Prefer `const` over `let`; never use `var` - Functional components only, no class components - Named exports for components, default export only for pages - Props interfaces above the component: `interface MyComponentProps { ... }` - No inline styles; use Tailwind classes - Error boundaries for async data fetching components ## Patterns to follow - Data fetching: use React Query (`useQuery`, `useMutation`), not `useEffect` with `fetch` - Forms: use React Hook Form + Zod for validation - API calls: go through `src/lib/apiClient.ts` — never call `fetch` directly in components - Error handling: return `Result<T, Error>` objects from service functions; do not throw in services ## File and folder naming - Components: PascalCase (`UserCard.tsx`) - Hooks: camelCase starting with `use` (`useUserProfile.ts`) - Utils and services: camelCase (`formatDate.ts`, `userService.ts`) - Test files: same name as the file being tested with `.test.` (`UserCard.test.tsx`) ## Things to avoid - No `console.log` in committed code (use the logger utility) - No hardcoded strings for UI copy (use translation keys) - No direct DOM manipulation (`document.querySelector` etc.) — use React refs
Example .cursorrules for a Python FastAPI backend
code# Project: API Backend ## Tech stack - Python 3.11 - FastAPI with Pydantic v2 for validation - SQLAlchemy 2.0 (async) with Alembic for migrations - PostgreSQL - Pytest for testing - Ruff for linting, Black for formatting ## Code style - Type annotations on all function signatures - Pydantic models for all request/response bodies - Prefer dataclasses or Pydantic models over raw dicts - No mutable default arguments - Raise HTTPException for HTTP errors; use custom exception handlers for domain errors ## Patterns - Repository pattern: database access only in `repositories/` folder - Service layer: business logic only in `services/` folder - Routers in `routers/` folder, each with its own prefix - Dependency injection via FastAPI `Depends()` - Async everywhere: all endpoints, services, and repositories must be async ## Testing - Unit tests for services (mock the repository layer) - Integration tests for endpoints (use test database) - Fixtures in `conftest.py`, not inside test files
How the AI uses .cursorrules
When you open Chat or Composer, Cursor prepends your .cursorrules content to the system prompt. This means the AI "knows" all of it before you even type your question. When you ask "add a new endpoint for deleting a user", the AI will automatically follow the repository pattern, use async/await, use HTTPException for errors, and write a test — because your rules say so.
Attaching context dynamically
Rules give persistent baseline context. For specific tasks, you also attach context dynamically using @:
@FileName– attaches a specific file. Use when the AI needs to see a model, a helper, or an existing similar feature.@FolderName– attaches all files in a folder. Use when asking about a module or asking the AI to follow patterns from a set of files.@Web– tells Cursor to search the web for documentation. Use for library APIs or features you are not sure the model knows.@Codebase– lets the AI search the whole project for relevant code. Use when you are not sure which files matter.
A practical example
You are adding a new service. You want it to follow the same pattern as userService.ts. In Composer:
code@userService.ts @productService.ts Add an orderService.ts in the services/ folder. It should expose: getOrders(userId), createOrder(userId, items), cancelOrder(orderId). Follow the exact same patterns as userService and productService for error handling, types, and logging.
By attaching two existing services, the AI copies the style rather than inventing its own.
Updating .cursorrules over time
Your rules file should evolve with the project. When you establish a new pattern, add it. When a library is replaced, update the entry. A good time to review and update it is during code review — if a PR comment says "this should use X pattern not Y", add X pattern to the rules so Composer follows it automatically next time.