Cursor Rules for Backend Development: Data Access, Validation, and APIs
Adaptable Cursor rules for backend projects: data access patterns, validation, interface design, and testing, with fenbs retaining accepted design decisions and exceptions shared across coding assistants.
Updated 4 min read
Cursor rules for backend development tell a coding assistant which data access patterns your project uses, how validation is handled, what an acceptable API interface looks like, and which testing approaches are expected. Without them, an assistant writes working backend code that slowly diverges from your team's conventions: raw SQL mixed with an ORM, inconsistent error formats, or tests that hit external services. fenbs retains the accepted design decisions and exceptions across sessions, so the assistant reads what the team has agreed on before adding a new endpoint or repository method.
These rules are technology-neutral by design. Adjust the examples to match your language, framework, and data store.
What backend Cursor rules need to cover
A backend codebase has several areas where implicit conventions accumulate into inconsistency over time. Data access is one: a project that started with a query builder may have drifted to raw SQL in some places and an ORM in others. Validation is another: if input is checked in some places and not others, the first unchecked path is a security gap. Rules that name the expected patterns in each area give an assistant a clear target. They also give a new team member a faster path to writing code that fits. Most backend conventions are reasonable once you understand the reason behind them, but they are invisible until someone reads them in the wrong order and asks why the codebase does not follow the tutorial approach.
- Data access: which abstraction is used, how queries are structured, and what a repository method looks like.
- Validation: where input is validated, what library or approach is used, and how errors are returned.
- Error handling: the error format, which errors are retried, and which are surfaced to the caller.
- API interfaces: REST or RPC conventions, versioning, status codes, and response shapes.
- Testing: which layer is tested with unit tests, which with integration tests, and which tools are used.
Data access rules
The most common data access problem in a mixed codebase is an N+1 query introduced by an assistant that does not know your loading strategy. A rule that describes how relations are loaded prevents that class of problem. A rule about raw SQL prevents a new raw query appearing in a codebase that uses an ORM.
Write the data access rules to match the maturity of your codebase. A project that is still consolidating around a repository pattern benefits from a rule that says "all new database calls must go through a repository class; do not add direct ORM queries in services or controllers." A more mature project may need a rule that names specific query helpers that are approved, because the assistant otherwise has too many equivalent ways to do the same thing and will choose inconsistently. A rule written in terms of actual codebase paths and method names is more useful than a general principle, because the assistant can check its own output against the specific file and pattern named rather than inferring what the rule means in context.
# Data access rules
## Repository pattern
All database access goes through a repository class in src/repositories/.
Do not write raw SQL or ORM queries in controllers, services, or use cases.
Repository methods use domain language: findByEmail(email), listActiveOrders(), not selectWhere().
## Query loading
Always specify eager loading when accessing relations to avoid N+1 queries.
List the relations you are loading explicitly:
userRepository.findById(id, { include: ['orders', 'profile'] })
Do not load all relations by default.
## Transactions
Wrap multi-step writes in a transaction.
Do not call two repository write methods in sequence without a transaction.
The repository or service that initiates the transaction is responsible for rolling it back on error.
## Raw SQL
Raw SQL is not used in this project. If a query requires it, raise it for discussion first.
Approved raw queries are in src/repositories/sql/ with a comment explaining why an ORM query was insufficient.Validation and error handling rules
Inconsistent validation is a security problem as much as a quality one. If the same field is validated at the controller in one endpoint and not another, the unchecked path is an attack surface. An error format that differs between endpoints breaks clients that parse error responses. Rules in this area need to be explicit about where validation happens and what the error output looks like.
# Validation and error handling
## Input validation
Validate all external input at the entry point (controller or route handler).
Use the project's schema library (Zod / Joi / class-validator — see package.json) for all validation.
Do not add ad hoc if/throw checks for input validation; use the schema library consistently.
## Validation errors
Return HTTP 400 for validation failures.
Include a machine-readable errors array:
{ "errors": [{ "field": "email", "message": "Invalid email address" }] }
Do not return a plain string for a validation error.
## Application errors
Use a typed error class hierarchy in src/errors/.
Catch typed errors at the controller and map them to status codes:
NotFoundError -> 404, ForbiddenError -> 403, ConflictError -> 409.
Do not catch and swallow errors without logging them.
## Unexpected errors
Log unexpected errors with the error message, stack, and request context.
Return HTTP 500 with a generic message to the caller; do not expose stack traces.API interface design rules
An API is a contract. An assistant that adds an endpoint with a different response shape, uses a different status code for the same situation, or skips versioning breaks clients silently. Rules in this area are most useful when they describe the conventions the existing API already follows, so new endpoints look like the rest.
# API interface rules
## REST conventions
Use noun resources in plural: /users, /orders, /products.
Use HTTP verbs: GET to read, POST to create, PUT or PATCH to update, DELETE to remove.
Avoid verbs in route paths: /orders/{id}/cancel is acceptable for state transitions;
/cancelOrder is not.
## Response shape
Successful single-resource responses wrap data in a top-level key:
{ "user": { "id": 1, "email": "..." } }
Collection responses include data and pagination:
{ "orders": [...], "meta": { "total": 100, "page": 1, "perPage": 20 } }
## Status codes
201 for successful resource creation. 204 for successful deletion with no body.
Do not return 200 for a creation or deletion.
## Versioning
This API uses URL versioning: /api/v1/. Do not add a new version without a discussion.
Breaking changes go in a new version; additive changes are backward compatible and do not require one.Testing rules
A test that makes a real network call to an external service is slow, flaky, and environment-dependent. An assistant without guidance may write integration tests against real services where unit tests with fakes would be faster and more reliable. Rules that say which layer to test in which way keep the test suite fast and informative.
# Backend testing rules ## Unit tests Unit test domain logic and use cases with fakes for all external dependencies. A unit test must not make a network call or write to a database. Use in-memory fakes from tests/fakes/ for repositories and external service ports. ## Integration tests Integration tests for repositories use a test database (see .env.test). Integration tests for HTTP handlers use a test server with real middleware. Tag integration tests; they run separately from unit tests in CI. ## What to test Test the public contract of a use case or service, not its internal steps. Do not test private methods. For API endpoints, test the response shape, status code, and error cases. ## Coverage Aim for full branch coverage on domain logic. Do not add tests that only assert that a method was called; assert the outcome.
Keep accepted design decisions where your AI finds them
fenbs stores Decisions and rules that connected assistants read first. When your team agrees on the error format, the repository pattern, or which testing library to use, record those in fenbs as standing rules. The next Cursor session on any endpoint reads the current agreed conventions before writing a line. fenbs does not make the decisions for you, but it makes sure the next assistant reads the ones you already made.
Create a free accountFree for one person · No credit card · Works with Claude, ChatGPT, Cursor and more
How to do this with fenbs
- Create a free account and add a project for your backend service.
- Record the key design decisions your team has settled: the data access pattern, the validation library, the error format, and the API versioning approach. Each one is a standing rule in fenbs.
- Add the Cursor rule files to
.cursor/rules/. Scope data access rules tosrc/repositories/**and API rules tosrc/routes/**or equivalent paths in your project. - Connect Cursor to fenbs over MCP from Integrations. Ask it to read the project context before working on a new endpoint or repository.
- When a new convention is agreed on or an old one changes, update both the fenbs Decision and the rule file. The two should always match.