Comprehensive Rules for designing, implementing, and operating production-grade asynchronous REST APIs with FastAPI.
Your FastAPI development just got a massive upgrade. These comprehensive Cursor Rules transform how you build, scale, and maintain production APIs—without the usual weeks of architectural decisions and refactoring cycles.
You know FastAPI is powerful, but every new project starts the same way: staring at a blank file wondering how to structure domains, where to put business logic, and how to avoid the async pitfalls that crash production systems. You end up with:
Meanwhile, your deployment pipeline breaks because Docker images are 800MB, health checks fail randomly, and you're still debugging why the database connection pool exhausts under moderate traffic.
These Cursor Rules implement a battle-tested, domain-driven architecture that eliminates architectural guesswork and accelerates development. Every API you build follows proven patterns for scalability, security, and maintainability.
src/
app/__init__.py # FastAPI() instance
core/
config.py # Environment & settings
security.py # JWT, OAuth, rate limiting
domains/
users/
router.py # Route definitions
schemas.py # Pydantic models
services.py # Business logic
repository.py # Data access
tests/ # Domain-specific tests
billing/...
inventory/...
Each domain is completely self-contained with its own routes, models, services, and tests. No more hunting through dozens of files to understand a single feature.
Every I/O operation is non-blocking by default. Database queries, HTTP calls, file operations, and Redis operations all use async patterns that keep your API responsive under load:
async def create_user(dto: UserCreate) -> UserOut:
if await repo.exists(dto.email):
raise HTTPException(status_code=409, detail="email_taken")
user = await repo.insert(dto)
await cache.invalidate(f"user:{user.id}")
return UserOut.model_validate(user)
CPU-bound work automatically runs in thread pools, preventing event loop blocking.
Skip the architectural decisions. Every new FastAPI project starts with proven structure, dependency injection, error handling, and testing patterns already configured.
Domain-driven structure means adding new features is just creating a new domain folder. Router, schemas, services, and tests follow identical patterns every time.
Built-in JWT handling, password hashing with Argon2, HTTPS enforcement, and rate limiting protect against the security issues that plague custom implementations.
Comprehensive error handling, health checks, structured logging, and monitoring integration catch problems before they reach users.
Before: 30 minutes of decisions about where to put validation, business logic, error handling, and tests.
After: 3 minutes to create the domain structure and implement the endpoint following established patterns:
# domains/products/router.py
@router.post("/", response_model=ProductOut, status_code=201)
async def create_product(
dto: ProductCreate,
current_user: User = Depends(require_user),
session: AsyncSession = Depends(get_db)
) -> ProductOut:
return await ProductService.create(dto, session)
The service layer, validation, error handling, and testing patterns are automatically consistent with every other endpoint.
Before: Hours configuring async database connections, connection pooling, session management, and repository patterns.
After: SQLModel integration with async sessions, automatic transaction management, and repository patterns that handle connection pooling, retries, and error recovery:
async def get_user_by_email(email: str, session: AsyncSession) -> User | None:
result = await session.execute(
select(User).where(User.email == email)
)
return result.scalar_one_or_none()
Before: Fighting with async test clients, database fixtures, and authentication mocking.
After: Complete testing infrastructure with async client fixtures, database session overrides, and authentication helpers:
async def test_create_user_success(async_client, override_get_db):
response = await async_client.post(
"/v1/users/",
json={"email": "[email protected]", "password": "secure123"}
)
assert response.status_code == 201
assert response.json()["email"] == "[email protected]"
Create a new .cursorrules file in your FastAPI project root and paste the complete rule set. Cursor immediately understands your project architecture and coding patterns.
Ask Cursor to create the domain-driven project structure. Within seconds, you have:
Create a new domain (users, products, orders) by asking Cursor to generate the complete domain structure. You get:
The included Docker and Kubernetes configurations create production-ready deployments with:
New FastAPI projects go from idea to deployed API in hours instead of weeks. The domain-driven architecture scales from single endpoints to complex microservices without refactoring.
Built-in error handling, monitoring, health checks, and security patterns prevent the common issues that cause production outages. Your APIs handle traffic spikes, database failures, and security attacks gracefully.
Every developer on your team follows identical patterns for routing, validation, business logic, and testing. Code reviews focus on business logic instead of architectural decisions.
Domain isolation means you can refactor, test, and deploy individual features without impacting the entire application. Technical debt stays contained to specific domains.
These Cursor Rules eliminate the complexity and guesswork from FastAPI development. You build production-grade APIs with confidence, knowing every pattern is battle-tested and every architectural decision is proven.
Ready to transform your FastAPI development workflow? Install these rules and experience the difference in your next API endpoint.
You are an expert in Python 3.12+, FastAPI, AsyncIO, Pydantic v2, SQLModel, PostgreSQL, Redis, Docker, Kubernetes, GitHub Actions, Ruff, MyPy.
Key Principles
- Architect every project around DDD-style domains (e.g., users, billing, inventory). Each domain contains its own router, schemas, services, and tests.
- Async-first mindset: every I/O path (`db`, `http`, `fs`, `redis`) is non-blocking; isolate CPU-bound work in `concurrent.futures.ThreadPoolExecutor`.
- Separate transport (route) layer from business logic (service layer) to maximise testability and SRP.
- Prefer pure, deterministic functions and immutability in service code. Side-effects live at the edge.
- Enforce type-safety everywhere (`from __future__ import annotations`; `mypy --strict`).
- Fail fast; validate early; return explicit, documented errors.
- Continuous delivery: code must pass Ruff, MyPy, Pytest, and contract tests before merge.
Python
- Always add explicit return types. Never use `Any` outside legacy shims.
- Use `match` statements for multi-branch logic instead of long `if/elif` chains.
- Prefer `Path("/tmp")` (pathlib) and `Enum` for finite states.
- Keep functions ≤ 40 LOC. Split when a function gains a second `if`.
- Naming
• modules: snake_case; • classes: PascalCase; • vars/fns: snake_case; • async context mgrs end with `_async`.
- Imports: stdlib, ⏎, third-party, ⏎, first-party (isort profile = black).
- Use Ruff (`ruff format .` + `ruff check --fix .`) instead of Black/Flake8.
Error Handling & Validation
- All inbound data is validated with Pydantic `BaseModel` (DTO).
- Surface domain errors with `HTTPException(status_code=40x, detail="…")`; never leak internal stack traces.
- Define a central exception handler that converts known exceptions → RFC 9457 problem-details JSON.
- Use early returns:
```python
async def create_user(dto: UserCreate) -> UserOut: # happy path last
if await repo.exists(dto.email):
raise HTTPException(status_code=409, detail="email_taken")
user = await repo.insert(dto)
return UserOut.model_validate(user)
```
- Validate JWT/OAuth scopes in a dependency so all routes share identical security semantics.
FastAPI
- Project layout:
```
src/
app/__init__.py # FastAPI() instance
core/config.py
core/security.py
domains/
users/
router.py
schemas.py
services.py
repository.py
tests/
products/…
```
- Routers: one per domain; file named `router.py`; prefix & tags derive from domain (e.g., `prefix="/users"`, `tags=["users"]`).
- Dependency Injection:
• Inject DB session (`async_sessionmaker`) as `Depends(get_db)`.
• Inject authenticated `CurrentUser` via `Depends(require_user)`.
- Response models are explicit (`response_model=UserOut`, `status_code=201`).
- Use `background_tasks.add_task()` for fire-and-forget I/O (e.g., send email).
- Versioning: include major version as prefix (`/v1/users`). Maintain a separate router for each breaking version.
SQLModel & Data Layer
- Use `SQLModel` for aggregate roots; keep them dumb (no behaviour).
- Async engine: `create_async_engine("postgresql+asyncpg://…", echo=False)`.
- Repositories expose CRUD as async methods; no ORM logic in routers.
- Batch writes with `async with session.begin(): …` to reduce round-trips.
Testing
- Use `pytest-asyncio` + `httpx.AsyncClient(app=app, base_url="http://test")`.
- Add fixtures: `async_session`, `override_get_db`, `token_headers`.
- Write at least one contract test per route verifying status code, schema, and error cases.
- Run coverage; threshold ≥ 95 %.
Performance
- Default Uvicorn workers: `workers = (CPU*2)+1`. Use `--loop uvloop`.
- Enable `httptools` parser.
- Cache expensive GETs in Redis (`asyncio TTLCache` fallback) with a domain-specific key schema.
- Profile with `pyinstrument -r html "-m uvicorn app.main:app --reload"`.
Security
- Store secrets solely in environment variables or HashiCorp Vault.
- Hash passwords with `argon2id` (passlib); never store plain or SHA.
- JWT: Use short (15 min) access + long refresh tokens; rotate keys via JWKs.
- Enforce HTTPS; set `secure`, `httponly`, `samesite=strict` cookies.
- Rate-limit sensitive endpoints via Redis token bucket.
CI/CD & Ops
- GitHub Actions: matrix Python [3.12, 3.11]; jobs: lint, typecheck, test, build-image, deploy.
- Dockerfile multi-stage: `poetry export --without-hashes > requirements.txt` → install in slim `python:3.12-alpine`.
- Health checks: `/health/live`, `/health/ready` with DB & Redis pings.
- Kubernetes:
• Readiness probe hits `/health/ready`.
• Resources: `requests {cpu: 100m, memory: 256Mi}`.
- Observability: structured JSON logs (loguru + `uvicorn.access`); trace with OpenTelemetry, export to Jaeger.
Documentation
- Write docstrings in Google style; FastAPI autogenerates OpenAPI.
- Tag each endpoint with descriptive `summary` and `description`.
- Expose `/docs` (Swagger) internally only; serve ReDoc externally.
Common Pitfalls & Guards
- Blocking DB drivers (psycopg2) → Always use asyncpg / SQLModel async.
- Large file uploads → stream with `StreamingResponse`.
- Circular imports → keep DI providers in `core/` not in domains.
- Silent background exceptions → add exception handler to `BackgroundTask` & log.
Checklist before merge
1. `ruff check --fix .` passes
2. `mypy --strict` passes
3. `pytest -q` & coverage ≥ 95 %
4. `docker build .` succeeds & image < 200 MB
5. `pytest tests/contracts` against staging OpenAPI
Ready to code 🚀