Chapter 7

.cursorrules Engineering — 4 Production-Ready Templates

Chapter 7: .cursorrules Engineering — 4 Production-Ready Templates

.cursorrules is a project specification written for AI — it tells Cursor what tech stack you use, what conventions you follow, and what's forbidden. Without it, AI guesses your preferences on every generation. With it, AI-generated code naturally fits your project's style. This chapter provides 4 ready-to-use production templates covering the most common full-stack scenarios.

How .cursorrules Works

Every time you open Cursor Chat or Composer, the contents of .cursorrules are automatically injected into the AI's system prompt. It's as if the AI reads your project specification at the start of every conversation.

What this gives you:

Template 1: React + TypeScript Full-Stack

# Tech Stack
- Frontend: React 18, TypeScript strict mode, Tailwind CSS v3
- Backend: Next.js 14 App Router, Server Actions
- Database: PostgreSQL + Prisma ORM
- Auth: NextAuth.js v5

# Code Style
- 2-space indent, single quotes, no semicolons (Prettier defaults)
- No `any` type — use `unknown` and narrow it explicitly
- Functional components only, no class components
- Custom hooks must start with `use`, placed in /src/hooks/
- All async functions must handle errors (try/catch or .catch())

# File Structure
/src/app/          → Next.js pages and layouts (App Router)
/src/components/
  /ui/             → Generic UI primitives (Button, Input, Modal)
  /features/       → Domain-specific components (UserProfile, OrderList)
/src/hooks/        → Custom React hooks
/src/lib/          → Utilities and third-party clients
/src/server/       → Server-only code (DB queries, auth helpers)

# API Conventions
- All API responses: { data: T | null, error: string | null }
- HTTP status: 200 ok, 201 created, 400 bad request, 401 unauthorized, 404 not found, 500 server error
- Never expose stack traces in API responses

# Forbidden
- No `useEffect` for data fetching — use React Query or Server Components
- No direct database queries in Client Components
- No hardcoded API keys or secrets in source code

Template 2: FastAPI + Python Backend

# Tech Stack
- Python 3.12, FastAPI, SQLAlchemy 2.0 (async), Alembic
- Database: PostgreSQL
- Auth: JWT (python-jose), bcrypt for password hashing
- Task Queue: Celery + Redis
- Testing: pytest, pytest-asyncio

# Code Style
- Follow PEP 8, use ruff for formatting
- All functions and methods must have type annotations
- Pydantic models for all request/response schemas — no raw dicts in API layer
- SQLAlchemy models in /app/models/, Pydantic schemas in /app/schemas/

# Error Handling
- Raise HTTPException with proper status codes in route handlers
- Service layer raises custom exceptions (defined in /app/exceptions.py)
- Never let raw SQLAlchemy exceptions bubble up to the API layer
- Log all 5xx errors with structlog

# Security
- All passwords hashed with bcrypt (min cost factor 12)
- JWT secrets from environment variables only
- SQL: always use parameterized queries or ORM — never string concatenation
- Validate all user input with Pydantic before use

# Directory Structure
/app/routers/      → API route handlers (thin layer, business logic in services)
/app/services/     → Business logic
/app/repositories/ → Database access layer
/app/models/       → SQLAlchemy ORM models
/app/schemas/      → Pydantic request/response models
/app/core/         → Config, dependencies, security utilities

Template 3: Go Microservice

# Tech Stack
- Go 1.22+, standard library preferred
- Web: net/http + chi router
- Database: PostgreSQL, pgx driver, sqlc for type-safe queries
- Config: viper (from environment variables)
- Logging: slog (structured, JSON format in production)
- Testing: stdlib testing + testify

# Code Style
- gofmt + golangci-lint strict
- Error wrapping: always fmt.Errorf("context: %w", err) — never discard errors
- CamelCase for exported, camelCase for unexported
- Interfaces defined at point of use, not in the implementing package

# Error Handling
- Return errors to caller — no panic in library code
- Sentinel errors for expected cases (ErrNotFound, ErrUnauthorized)
- Wrap with context at every layer crossing

# Package Layout
/cmd/server/       → main.go, only wiring
/internal/
  /handler/        → HTTP handlers (thin, delegate to service)
  /service/        → Business logic
  /repository/     → Database access
  /domain/         → Domain types and interfaces
/pkg/              → Public reusable packages

# Forbidden
- No global state except logger and metrics
- No init() functions with side effects
- No ORM — use sqlc generated code for type safety

Template 4: Node.js + Prisma Backend

# Tech Stack
- Node.js 20 LTS, TypeScript strict
- Framework: Express 4.x
- ORM: Prisma 5
- Auth: JWT (jsonwebtoken), bcrypt
- Validation: zod
- Testing: Jest + Supertest

# Code Style
- 2-space indent, single quotes, semicolons required
- All route handlers must be async
- Zod schema validation on all request bodies before processing
- Error-first middleware pattern: (err, req, res, next)

# Project Structure
/src/routes/       → Express route definitions
/src/controllers/  → Request/response handling (thin)
/src/services/     → Business logic
/src/repositories/ → Prisma DB access
/src/middleware/   → Auth, error handling, logging
/src/lib/          → Utility functions
/src/types/        → Shared TypeScript types

# Database
- Use Prisma transactions for multi-step writes
- Always select only needed fields — avoid select *
- Use cursor-based pagination for large datasets

# Security
- JWT secrets from process.env only
- No raw SQL string concatenation — use Prisma or parameterized queries
- Rate limiting on all public endpoints
- Sanitize all user input before logging (mask PII)

Verifying That .cursorrules Is Active

After writing .cursorrules, use these two methods to verify it's working:

Method 1: Ask AI in Chat

Do you know the tech stack and code conventions for this project?
Please describe the key rules.

If the AI accurately describes what you wrote in .cursorrules, it's being read correctly.

Method 2: Generate a test file

Create a UserService for testing with getUserById and updateUser methods,
following the project conventions. No explanatory comments.

Check the generated code: naming style, error handling, import style — do they all match your spec?

Common Diagnostic Issues

Problem Likely cause Fix
Generated code doesn't match conventions .cursorrules not being read Check: is the file in project root? Is the filename spelled correctly?
AI ignores a specific rule Rule description is too vague Change "should use X" to "must use X, forbidden to use Y"
Inconsistent style between generations .cursorrules lacks specific constraints Add real code examples — more effective than describing rules
AI imports packages not in package.json No explicit ban Add a Forbidden section listing banned actions

Domain Knowledge Injection

.cursorrules isn't just code conventions — it can also inject business domain knowledge:

# Domain Knowledge
- "User" in our system refers to B2B customers (companies), not consumers
- Order status flow: draft → pending → paid → shipped → delivered / cancelled
- All amount fields are stored in cents (integer), not dollars
- userId in the database is UUID; in URL params it's encoded as base64url

Without this, AI applies generic assumptions that conflict with your business logic.

Chapter Key Points

  1. .cursorrules is the upfront context for every conversation: Write it once, every conversation benefits — the highest-leverage one-time investment.
  2. Four templates cover the main scenarios: React+TS, FastAPI, Go microservice, Node.js+Prisma — copy and customize directly.
  3. Rules must be specific, not vague: "Must use X, forbidden to use Y" is ten times more effective than "should use X."
  4. The Forbidden section is your defense line: Explicitly list prohibited patterns; prevent AI from taking shortcuts with approaches you don't want.
  5. Domain knowledge matters as much as code conventions: Business terminology, state flows, field units — write them in so AI understands your business context.
Rate this chapter
4.6  / 5  (45 ratings)

💬 Comments