●WWDC — WWDC 2026 confirms Siri runs on Google Gemini; third-party handoff to ChatGPT is dropped, and Siri AI won't ship in the EU under the DMA at iOS 27●BILLING — 6 days until the Jun 15 change: Agent SDK, headless Claude Code, GitHub Actions, and third-party agents move to API-rate monthly credit●OUTAGE — claude.ai, Claude Code, and Cowork saw an outage (Jun). Scheduled runs are safest when built around fallbackModel and retries●DYNAMIC-WORKFLOWS — Dynamic workflows are on by default on Max/Team and the API, for codebase-wide bug hunts and independent verification●ULTRACODE — Claude Code's new ultracode setting sits in the effort menu, fixing effort to xhigh while Claude decides when to run a workflow●OPUS4.8 — Claude Opus 4.8 is settled in as the default across major plans, with stronger coding, agentic, and reasoning skills●WWDC — WWDC 2026 confirms Siri runs on Google Gemini; third-party handoff to ChatGPT is dropped, and Siri AI won't ship in the EU under the DMA at iOS 27●BILLING — 6 days until the Jun 15 change: Agent SDK, headless Claude Code, GitHub Actions, and third-party agents move to API-rate monthly credit●OUTAGE — claude.ai, Claude Code, and Cowork saw an outage (Jun). Scheduled runs are safest when built around fallbackModel and retries●DYNAMIC-WORKFLOWS — Dynamic workflows are on by default on Max/Team and the API, for codebase-wide bug hunts and independent verification●ULTRACODE — Claude Code's new ultracode setting sits in the effort menu, fixing effort to xhigh while Claude decides when to run a workflow●OPUS4.8 — Claude Opus 4.8 is settled in as the default across major plans, with stronger coding, agentic, and reasoning skills
Claude Code × Python FastAPI Production Guide 2026 — From Architecture to Docker Deployment with AI Pair Programming
A complete advanced guide to building production-ready Python FastAPI servers using Claude Code as your AI pair programmer. Covers Pydantic v2, pytest automation, Docker, and CI/CD with practical code examples throughout.
Setup and context — How Claude Code Transforms FastAPI Development
FastAPI has become the de facto standard for Python backend development, offering type safety, high performance, and native async support. Yet taking a project from initial design all the way to a production-ready deployment with comprehensive testing still demands significant time and expertise, especially for solo developers.
Claude Code changes that equation dramatically. Used as a true AI pair programmer, it can generate architecture scaffolding, implement business logic, write pytest test suites, configure Docker containers, and set up CI/CD pipelines — all with minimal manual effort.
Who This Article Is For
This guide is written for developers who:
Know Python and FastAPI basics but want to level up to production-quality architecture
Have started using Claude Code but aren't sure how to apply it to backend development
Want to automate pytest, Docker, and CI/CD workflows using Claude Code
Are building a SaaS product, freelance API, or side project and need to move fast without sacrificing quality
By the end, you'll have a complete mental model — and working code — for shipping FastAPI APIs to production with Claude Code as your co-developer.
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦Learn the exact prompting strategies to use Claude Code for accelerating FastAPI project design, coding, and testing
✦Master the full production workflow — pytest, Docker, GitHub Actions CI/CD — with working code you can use immediately
✦Discover how to combine Claude Code's multi-agent and Hooks features to automatically maintain backend API quality
Secure payment via Stripe · Cancel anytime
CLAUDE.md Design — Giving Your AI the Right Context
The quality of code Claude Code generates depends directly on how well it understands your project. CLAUDE.md is your technical specification document for Claude Code — the difference between getting generic boilerplate and production-quality code.
Writing an Effective CLAUDE.md
Place this file at the root of your project:
# FastAPI Production API — CLAUDE.md## Technology Stack- Python 3.12 / FastAPI 0.115+ / Uvicorn- SQLAlchemy 2.0 (async) + asyncpg (PostgreSQL)- Pydantic v2 (strict validation mode)- JWT authentication (python-jose + passlib bcrypt)- pytest-asyncio + httpx (async testing)- Docker + docker-compose## Coding Standards- All functions and classes must have full type hints- Use async/await consistently — never mix sync and async code- All endpoint response models must be defined with Pydantic schemas- Database sessions must be obtained via Depends() dependency injection- HTTPExceptions are centralized in app/core/exceptions.py## Testing Standards- Write pytest tests alongside every new feature- Unit tests: pure functions in app/core/- Integration tests: use real DB (in-memory SQLite for tests)- Coverage target: 80% minimum## Prohibited Patterns- Global mutable state- print() debugging (use logging module)- Hardcoded credentials (environment variables only)
With this context in place, Claude Code will automatically know to use async SQLAlchemy, write pytest-asyncio tests, and maintain type safety throughout — without needing to be reminded on every prompt.
Step 1: Project Initialization — Generating the Scaffold
Start Claude Code and let it create the entire project foundation in one shot:
mkdir fastapi-app && cd fastapi-app# Place CLAUDE.md first (content above)claude
Use this prompt:
Following the CLAUDE.md specifications, generate the complete project scaffold
for a production FastAPI API.
Required files:
1. app/core/config.py — environment variable management using pydantic-settings
2. app/core/database.py — SQLAlchemy 2.0 async engine + session factory
3. app/core/security.py — JWT access token generation and verification
4. app/main.py — lifespan events, CORS middleware, health endpoint
5. requirements.txt — pinned versions
6. pyproject.toml — ruff + mypy configuration
Create all files now.
Generated Code Example
Here's the app/core/config.py Claude Code produces:
# app/core/config.pyfrom pydantic_settings import BaseSettings, SettingsConfigDictfrom functools import lru_cacheclass Settings(BaseSettings): """Application settings — auto-loaded from environment variables.""" model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", case_sensitive=False, ) # Application app_name: str = "FastAPI Production API" app_version: str = "1.0.0" debug: bool = False # Database database_url: str = "postgresql+asyncpg://user:password@localhost/dbname" database_pool_size: int = 10 database_max_overflow: int = 20 # JWT secret_key: str # Required: use 256-bit random string in production algorithm: str = "HS256" access_token_expire_minutes: int = 30 # CORS allowed_origins: list[str] = ["http://localhost:3000"]@lru_cachedef get_settings() -> Settings: """Return singleton settings instance (for DI).""" return Settings()
The @lru_cache pattern ensures settings are loaded only once per process, which is important when using Depends(get_settings) across many request handlers. Claude Code applies these kinds of production best practices automatically when the CLAUDE.md sets clear expectations.
Step 2: Model and Schema Design — Pydantic v2 × SQLAlchemy 2.0
When designing models with Claude Code, the key is providing rich, specific requirements rather than vague descriptions:
Create app/models/user.py and app/schemas/user.py.
User model requirements:
- id: UUID (auto-generated)
- email: unique constraint, max 255 chars
- hashed_password: str
- is_active: bool (default True)
- is_superuser: bool (default False)
- created_at / updated_at: auto-managed timestamps
Three Pydantic schemas:
- UserCreate: for registration input (plain text password)
- UserRead: for API responses (password excluded)
- UserUpdate: for partial updates (all fields Optional)
Use SQLAlchemy 2.0 Mapped[T] annotation style throughout.
SQLAlchemy 2.0's Mapped[T] annotations provide full IDE autocomplete and pass mypy's strict type checking — a major quality-of-life improvement over the older column declaration style. Claude Code generates this modern syntax automatically when you specify the version in CLAUDE.md.
Step 3: API Endpoint Development
For endpoint generation, describe your requirements layer by layer:
Implement app/api/v1/users.py.
Endpoints:
- POST /users/ — new user registration (with duplicate email check)
- GET /users/me — get current authenticated user
- GET /users/{user_id} — get user details (superusers only)
- PATCH /users/{user_id} — update user information
- DELETE /users/{user_id} — soft delete (set is_active=False)
Requirements:
- All endpoints use async def
- DB operations use SQLAlchemy AsyncSession via Depends
- Authentication check via get_current_user dependency
- Return appropriate HTTPExceptions (400/401/403/404)
- All responses typed with UserRead schema
With response_model=UserRead, FastAPI automatically excludes hashed_password from the response — no manual filtering required.
Step 4: pytest Test Suite — Full Async API Testing
FastAPI + SQLAlchemy async testing requires some non-trivial setup. Claude Code handles this complexity gracefully when given the right prompt:
Create tests/conftest.py.
Requirements:
- Use in-memory SQLite (aiosqlite) as the test database
- Reset the database before each test for complete isolation
- Use pytest-asyncio with asyncio_mode = "auto"
- Test endpoints using httpx.AsyncClient
- Fixtures: normal user, superuser, JWT tokens
- Also create pytest.ini with asyncio_mode = auto
The generated tests/conftest.py:
# tests/conftest.pyimport pytestimport pytest_asynciofrom httpx import AsyncClient, ASGITransportfrom sqlalchemy.ext.asyncio import AsyncSession, create_async_enginefrom sqlalchemy.pool import StaticPoolfrom app.main import appfrom app.core.database import Base, get_dbfrom app.core.security import get_password_hash, create_access_tokenfrom app.models.user import UserTEST_DATABASE_URL = "sqlite+aiosqlite:///:memory:"test_engine = create_async_engine( TEST_DATABASE_URL, connect_args={"check_same_thread": False}, poolclass=StaticPool, # Required for in-memory sharing)@pytest_asyncio.fixture(autouse=True)async def setup_db(): """Create tables before each test; drop them after.""" async with test_engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) yield async with test_engine.begin() as conn: await conn.run_sync(Base.metadata.drop_all)@pytest_asyncio.fixtureasync def db_session(): async with AsyncSession(test_engine) as session: yield session@pytest_asyncio.fixtureasync def client(db_session: AsyncSession): """FastAPI test client with database overridden.""" app.dependency_overrides[get_db] = lambda: db_session async with AsyncClient( transport=ASGITransport(app=app), base_url="http://test" ) as ac: yield ac app.dependency_overrides.clear()@pytest_asyncio.fixtureasync def normal_user(db_session: AsyncSession) -> User: user = User( email="test@example.com", hashed_password=get_password_hash("testpassword123"), ) db_session.add(user) await db_session.commit() await db_session.refresh(user) return user@pytest_asyncio.fixturedef user_token(normal_user: User) -> str: return create_access_token(subject=str(normal_user.id))
The app.dependency_overrides pattern is the cornerstone of effective FastAPI testing. By swapping the production database dependency with an in-memory test fixture, tests remain completely isolated, fast, and reproducible.
Step 5: Advanced Error Handling and Middleware Architecture
Production APIs need centralized, consistent error handling. Claude Code excels at generating boilerplate-heavy but critical infrastructure code like this.
Custom Exception Hierarchy
Create app/core/exceptions.py with a custom exception hierarchy.
Requirements:
- Base AppException with status_code, detail, and error_code fields
- Subclasses: NotFoundError, ValidationError, AuthenticationError, PermissionError
- FastAPI exception handler that converts these to JSON responses
- Include request_id in every error response for tracing
With this pattern, every error your API returns follows a consistent structure. Frontend clients can check error.code to handle specific error types programmatically, rather than parsing free-form error strings.
Request Logging Middleware
# app/core/middleware.pyimport timeimport uuidimport loggingfrom fastapi import Request, Responselogger = logging.getLogger(__name__)async def logging_middleware(request: Request, call_next) -> Response: """Log all requests with timing and correlation IDs.""" request_id = str(uuid.uuid4())[:8] start_time = time.perf_counter() # Attach request_id to request state for use in handlers request.state.request_id = request_id response = await call_next(request) duration_ms = (time.perf_counter() - start_time) * 1000 logger.info( "HTTP request", extra={ "request_id": request_id, "method": request.method, "path": request.url.path, "status_code": response.status_code, "duration_ms": round(duration_ms, 2), }, ) return response
Every request now produces a structured log entry with timing data. This makes debugging production issues dramatically easier because you can filter logs by request_id and see the full request lifecycle.
Step 6 (Extended): Async Background Tasks and Rate Limiting
Background Task Pattern
For operations that shouldn't block the request-response cycle — sending emails, generating reports, updating caches — use FastAPI's BackgroundTasks:
# app/api/v1/users.py (extended)from fastapi import BackgroundTasksfrom app.services.email import send_welcome_email@router.post("/", response_model=UserRead, status_code=status.HTTP_201_CREATED)async def create_user( user_in: UserCreate, background_tasks: BackgroundTasks, db: AsyncSession = Depends(get_db),) -> UserRead: """Register user and send welcome email in the background.""" # ... user creation logic ... db_user = User(email=user_in.email, hashed_password=hashed_pw) db.add(db_user) await db.commit() await db.refresh(db_user) # Enqueue welcome email — doesn't block the response background_tasks.add_task(send_welcome_email, email=db_user.email) return db_user
For more demanding workloads, ask Claude Code to generate a Celery + Redis configuration. The prompt pattern is: "Add Celery task queue support with Redis as the broker. Create a tasks.py with an example email-sending task, and show how to trigger it from a FastAPI endpoint."
Simple Rate Limiting with slowapi
Rate limiting is often overlooked until an API gets abused. Claude Code can add it quickly:
With this configuration, every time Claude Code writes or edits a file, pytest runs automatically. When a test fails, Claude Code sees the output and attempts a fix — establishing a tight "generate → test → fix" loop that produces substantially better code than a single-pass generation approach.
Create a production-grade Dockerfile.
Requirements:
- Multi-stage build (builder + runtime stages)
- python:3.12-slim base image
- Run as non-root user (security best practice)
- .dockerignore to exclude unnecessary files
- Target image size under 200MB
- Health check configuration
This pipeline runs linting, type checking, and tests on every PR. Coverage must stay above 80% or deployment is blocked. It deploys automatically to Fly.io on every merge to main.
Step 8: Multi-Agent Code Review Automation
Building on the patterns in the Claude Code Multi-Agent Practical Guide, you can run a dedicated review agent in parallel with your main development session.
Create .claude/review_agent.md:
# FastAPI Code Review AgentYou are a FastAPI security and performance specialist reviewer.## Review priorities (in order)1. Security: SQL injection, auth bypass, privilege escalation risks2. N+1 queries: Loop-based SELECT statements (suggest selectinload/joinedload)3. Type safety: Gaps in Pydantic validation4. Async safety: Blocking sync calls (e.g., requests library instead of httpx)5. Error handling: Appropriate use of HTTPException## Output formatFor each issue:- Location: filename:line_number- Severity: CRITICAL / WARNING / INFO- Issue: What's wrong- Fix: Specific code example
Running this review agent as a subagent in a separate Claude Code session creates continuous parallel review — you develop in one session while the other watches for quality regressions.
Performance Optimization Patterns
Connection Pool Tuning
One of the most common production issues with FastAPI + SQLAlchemy async is connection pool exhaustion under load. Here's how to configure it correctly:
The expire_on_commit=False setting is particularly important in async contexts. Without it, accessing model attributes after a commit() triggers additional database queries, which can cause "MissingGreenlet" errors in async code.
Eager Loading to Prevent N+1 Queries
Ask Claude Code to audit your queries with this prompt: "Review all SQLAlchemy queries in the project and identify any that will cause N+1 problems when relationships are accessed. Add appropriate selectinload or joinedload options."
Example of what it will convert:
# BEFORE: N+1 problem — fetches each user's items in a separate queryusers = await db.execute(select(User))for user in users.scalars(): print(user.items) # Triggers a new SELECT per user!# AFTER: Single query with eager loadingfrom sqlalchemy.orm import selectinloadstmt = select(User).options(selectinload(User.items))result = await db.execute(stmt)users = result.scalars().all()# All items loaded in ONE additional query — no N+1
Response Caching with Redis
For read-heavy endpoints, add Redis caching:
# app/core/cache.pyimport jsonimport redis.asyncio as redisfrom functools import wrapsfrom typing import Any, Callableredis_client = redis.from_url("redis://localhost:6379", decode_responses=True)def cache(ttl_seconds: int = 300, key_prefix: str = ""): """Decorator to cache endpoint responses in Redis.""" def decorator(func: Callable) -> Callable: @wraps(func) async def wrapper(*args, **kwargs) -> Any: # Build cache key from function name + arguments cache_key = f"{key_prefix}:{func.__name__}:{str(kwargs)}" cached = await redis_client.get(cache_key) if cached: return json.loads(cached) result = await func(*args, **kwargs) await redis_client.setex(cache_key, ttl_seconds, json.dumps(result)) return result return wrapper return decorator# Usage in endpoint@router.get("/items/popular", response_model=list[ItemRead])@cache(ttl_seconds=60, key_prefix="items")async def get_popular_items(db: AsyncSession = Depends(get_db)): """Returns popular items, cached for 60 seconds.""" ...
When you tell Claude Code "add Redis caching to the GET endpoints that don't require user-specific data," it will identify the right endpoints, add the decorator, and update docker-compose.yml to include a Redis service — all in a single pass.
Pre-Deployment Production Checklist
Before deploying to Fly.io or Railway, verify these items:
Security
SECRET_KEY is a 256-bit random string (openssl rand -hex 32)
ALLOWED_ORIGINS contains only your production domain(s)
DEBUG=false in production
No known vulnerabilities in dependencies (pip audit)
Performance
Database connection pool size is appropriate for production load
Heavy operations are offloaded to BackgroundTasks or a task queue
No N+1 queries (verify with echo=True on the SQLAlchemy engine)
Observability
Structured logging is configured (structlog recommended)
/health endpoint checks database connectivity
Error tracking service (Sentry, Datadog, etc.) is configured
Deploy to Fly.io:
fly launch --name my-fastapi-app --region nrtfly secrets set SECRET_KEY="$(openssl rand -hex 32)"fly secrets set DATABASE_URL="postgresql+asyncpg://..."fly deployfly status && fly logs
Summary
In this guide, we've covered the complete Claude Code × Python FastAPI production workflow — from CLAUDE.md design through deployment.
Key takeaways:
CLAUDE.md is the foundation: Explicit technology stack, coding standards, and constraints dramatically improve code generation quality
Iterative prompting wins: Step-by-step instructions produce better results than trying to generate everything at once
Co-generate tests: Requesting endpoint and pytest tests together eliminates the "I'll write tests later" trap
Hooks create feedback loops: Auto-running tests on every file save turns Claude Code into a self-correcting developer
Claude Code is not just a code generator — it's a capable pair programmer that handles design decisions, debugging, and test writing. Combine the patterns in this guide and you'll be shipping production-quality FastAPI APIs faster than ever before.
Share
Thank You for Reading
Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.