FastAPI a Year In: Where It Genuinely Shines, and Where the Honeymoon Ended

By James Nguyen Updated September 24, 2026
FastAPI a Year In: Where It Genuinely Shines, and Where the Honeymoon Ended

A year running FastAPI in production across two real services gave me enough time to separate the genuine, lasting advantages from the launch-day excitement that inevitably fades once a project matures past its initial, greenfield phase into something with real accumulated complexity.

Automatic Documentation Is Still the Standout Feature

The interactive Swagger documentation generated automatically from your Pydantic models and route definitions has continued to pay off well past the initial setup, saving genuine time onboarding new team members and giving frontend developers a working, testable API reference without needing separate documentation maintained by hand.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float

@app.post("/items/")
async def create_item(item: Item) -> Item:
    return item

Dependency Injection, Genuinely Useful Beyond the Basics

FastAPI's dependency injection system, initially something I used purely for database session management, turned out to scale well into more complex authorization logic, request-scoped caching, and rate limiting, letting me compose these concerns cleanly rather than tangling them into route handler logic directly.

from fastapi import Depends

async def get_current_user(token: str = Depends(oauth2_scheme)):
    return await verify_token(token)

@app.get("/profile")
async def read_profile(user: User = Depends(get_current_user)):
    return user

Async Performance, Real But Requires Actual Async Code

The performance benefits genuinely materialize only when your route handlers and their downstream calls, database queries, external API calls, actually use async libraries throughout. A route calling a synchronous database driver inside an async function blocks the event loop just as it would in any other async framework, and this caught our team out early before we fully understood the implication.

Where Validation Errors Became a Genuine Time Saver

Pydantic's automatic request validation, rejecting malformed requests with clear, structured error messages before they ever reach your business logic, eliminated an entire category of defensive validation code we would have otherwise had to write and maintain by hand across every endpoint.

The Dependency Version Churn

Across the year, both FastAPI and its underlying Pydantic dependency shipped breaking changes that required real migration work, particularly the jump between major Pydantic versions, which changed validator syntax significantly enough that upgrading wasn't a simple version bump.

Background Tasks: Useful for Simple Cases, Not a Real Queue Replacement

The built-in BackgroundTasks feature works well for genuinely lightweight, fire-and-forget work, sending a confirmation email after a request completes, but we learned the hard way it's not a substitute for a real task queue once background work started needing retries, monitoring, or genuine reliability guarantees, and migrated that heavier work to Celery instead.

WebSocket Support, Solid But Less Polished Than the REST Story

Building a real-time notification feature using FastAPI's WebSocket support worked, but documentation and community examples for genuinely production-grade WebSocket patterns, reconnection handling, scaling across multiple server instances, were noticeably thinner than the extensive resources available for standard REST endpoints.

Testing Story

The TestClient, built on top of the underlying Starlette framework, made writing integration tests for API endpoints genuinely straightforward, and combined with pytest fixtures for database setup and teardown, our test suite for both services has stayed fast and reliable across a year of active development.

Would I Choose It Again

Yes, without much hesitation, for any new Python API service. The documentation generation and dependency injection system alone justify the choice for most projects, and the rough edges I've hit, dependency version churn, background task limitations, are genuinely manageable once you know to plan around them rather than discovering them mid-project the way we did.

Daniel Justin

About the Author

James Nguyen is a full-stack programmer with more than ten years of experience engineering software systems. Specializing in the Node.js and Python ecosystems, he focuses on backend architecture, API design, and clean data integration. Follow me on YouTube and Instagram.

More Articles