All 5 AI packs for $39 →
← ToolTier Library
Cursor rules · Free

Cursor rules for FastAPI (Pydantic v2, deps, tests)

A free Cursor rule (.mdc) for FastAPI projects: response models on every route, Annotated dependencies, lifespan instead of startup events, pydantic-settings, Pydantic v2 APIs and dependency overrides in tests.

Install
.cursor/rules/fastapi.mdc
Last tested
Cursor / FastAPI 0.162 + Pydantic v2 · 2026-10-29

AI assistants trained on years of older FastAPI code keep writing patterns the framework has moved past: @app.on_event("startup") handlers, Pydantic v1 calls like .dict() and class Config, and routes that return database models directly. This rule steers Cursor's agent to current conventions. It's an Apply Intelligently rule (alwaysApply is false and there's a description), so the agent pulls it in when a task touches your FastAPI code.

The guidance follows FastAPI's own docs, checked on October 29, 2026, when the latest release on PyPI was 0.162.0: declare dependencies with Annotated and share them as aliases, use the lifespan context manager (the docs mark startup and shutdown events as deprecated), and swap dependencies in tests with app.dependency_overrides. It also flags the most common performance bug in AI-written FastAPI code: blocking calls inside async def routes.

Replace the [bracketed] values with your Python version, ORM, migration tool and test commands. If the same repo has a Next.js or Supabase front end, pair it with our free Supabase rule, and drop an AGENTS.md at the root so other agents get the same commands.

fastapi.mdc
---
description: FastAPI + Pydantic v2 conventions for routes, dependencies, settings, errors and tests. Use when editing FastAPI apps, routers, schemas, dependencies or their tests.
alwaysApply: false
---

# FastAPI: routes, dependencies, settings and tests

Stack: Python [3.12], FastAPI, Pydantic v2, [SQLAlchemy 2.x | SQLModel | none], pytest. If something here disagrees with the installed package versions or the official docs, the docs win. Check `pyproject.toml` before using an API, and never invent a FastAPI or Pydantic parameter.

## Layout
- `app/main.py` creates the app and includes routers. No route logic lives there.
- `app/routers/<area>.py`: one `APIRouter` per area, with its own `prefix` and `tags`.
- `app/schemas/`: Pydantic request and response models. `app/models/`: database models. Never return a database model directly from a route.
- `app/deps.py`: shared dependencies (DB session, current user, settings).
- `tests/` mirrors `app/`.

## Routes
- Every route declares a `response_model` (or a return type annotation) so output is validated and filtered. Separate `XCreate`, `XUpdate` and `XRead` schemas; never echo password hashes, tokens or internal ids that the client shouldn't see.
- Use the right status codes: `201` for creates, `204` for deletes with no body, `404` when the resource doesn't exist or the user can't see it.
- Raise `HTTPException` with a short, user-safe `detail`. Never return stack traces, SQL or secrets in an error.
- Use `async def` only when everything awaited inside is async. A blocking call (sync DB driver, `requests`, file I/O) inside `async def` stalls the event loop: make the route a plain `def` or use an async client.

## Dependencies
- Declare dependencies with `Annotated`, and define reusable aliases once in `app/deps.py`:
  `SessionDep = Annotated[Session, Depends(get_session)]`, `CurrentUser = Annotated[User, Depends(get_current_user)]`.
- Auth checks live in a dependency, not copied into each route. A route that needs a signed-in user takes `CurrentUser`.
- Resources opened per request (DB sessions, clients) use a `yield` dependency so they are always closed.

## Startup, shutdown and settings
- Use the `lifespan` async context manager passed to `FastAPI(lifespan=...)`. Don't add new `@app.on_event("startup")` or `"shutdown"` handlers; the FastAPI docs mark them deprecated.
- Load configuration with `pydantic-settings` (`BaseSettings`) from environment variables. No secrets in code, defaults or tests. Read settings through a cached `get_settings()` dependency so tests can override it.

## Pydantic v2
- Use v2 APIs: `model_config = ConfigDict(...)`, `model_dump()`, `model_validate()`, `field_validator`. Don't write v1-style `class Config`, `.dict()`, `.parse_obj()` or `@validator` in new code.
- Constrain inputs at the schema (`Field(min_length=..., ge=...)`, `EmailStr`, enums) instead of checking by hand in the route.

## Database
- Don't create tables at import time. Schema changes go through migrations ([Alembic]) committed with the code that needs them.
- Ask before anything destructive: dropping tables or columns, deleting without a filter, or running migrations against anything but a local database.

## Tests
- Use `fastapi.testclient.TestClient` (or `httpx.AsyncClient` with `ASGITransport` for async tests).
- Swap dependencies with `app.dependency_overrides[...]` in fixtures, and clear the overrides after each test.
- Every new route gets at least one test for the happy path and one for its main failure (validation error, 401/403 or 404).
- Run `[pytest -q]` and `[ruff check .]` before saying a change is done, and report what actually ran.
Works with: Cursor
CursorFastAPIPythonPydantic

← More free rules, templates and prompts

+ Your logo here