The Evolution of FastAPI (Part 1): Type Hints, PEP 649, and Pydantic v2
For several years, I had been avoiding creating a new framework. At first, I tried many different frameworks, plugins, and tools to solve everything FastAPI now covers… At some point, there was no choice but to create something myself.
This admission by FastAPI creator Sebastián Ramírez (tiangolo), in the official documentation’s History, Design and Future, captures the origins of this modern Python web framework.
FastAPI was officially released in December 2018, a full eight years after Flask appeared in 2010. Yet in the 2024 JetBrains Python Developers Survey, FastAPI led with 38% usage, ahead of Django (35%) and Flask (34%), emerging as the most widely used web framework in the Python ecosystem.
FastAPI spread quickly through a mature Python web landscape because it landed squarely on three technical turning points: Python 3.6+ variable annotation syntax, the asynchronous ASGI foundation provided by Starlette, and Pydantic’s ability to turn type declarations into runtime validation.
This is the first of a two-part series tracing FastAPI’s technical evolution from 2018 to 2026. It explores how FastAPI, a framework composed from existing components, grew to influence the direction of Python’s type annotation standards alongside Pydantic.
Standing on the Shoulders of Giants: The Opening Left by APIStar and FastAPI’s Birth in 2018
In its official list of alternatives and inspirations, FastAPI names the projects it learned from: Django REST Framework (DRF) demonstrated the value of automatic API documentation; Flask offered a model of concise microframework routing; Requests provided intuitive HTTP semantics; and the TypeScript framework NestJS informed its approach to dependency injection and editor-first development.
Of all these influences, APIStar had the deepest impact. FastAPI’s documentation calls the framework a “spiritual successor” to APIStar and offers a brief assessment:
“It inspired FastAPI to exist.”
Tom Christie's Transition (2018)
+-----------------------+ +-----------------------+
| APIStar | Pivoted | Starlette |
| (Typed API Framework) | ------> | (Async Toolkit) |
+-----------------------+ +-----------------------+
| |
| Left the niche open | ASGI base
v v
+---------------------------------------------------------+
| FastAPI (2018) |
| - Type hints + Pydantic |
| - Starlette on steroids |
+---------------------------------------------------------+
APIStar was an experimental framework created in 2017 by DRF creator Tom Christie. It was an early exploration of declaring web APIs through type hints. In September 2018, however, Christie announced that APIStar would become a framework-agnostic API toolkit and shifted his development focus to the newly created ASGI microframework Starlette.
APIStar’s pivot left an opening for an API framework built around type hints. At the same time, Starlette supplied a new asynchronous foundation. These two developments set the stage for FastAPI’s birth.
Three months later, on December 5, 2018, Sebastián Ramírez made the first GitHub commit. He released FastAPI 0.1.0 on PyPI on December 8.
Core Design Philosophy: Turning Type Hints from “Annotations” into “Specifications”
Architecturally, FastAPI has three layers, from bottom to top:
- Uvicorn: The high-performance ASGI server at the bottom, responsible for connection management and network transport.
- Starlette: The asynchronous microframework in the middle, providing routing, middleware, and WebSocket support.
- FastAPI: The layer on top, which builds on Starlette to add data validation, dependency injection, and OpenAPI documentation generation.
FastAPI’s documentation describes it as “Starlette on steroids.” This means FastAPI’s performance ceiling depends directly on Starlette and Uvicorn, while its underlying asynchronous behavior and middleware mechanisms are closely tied to Starlette.
+-------------------------+
| FastAPI |
| - Validation (Pydantic) |
| - Dependency injection |
| - OpenAPI docs (/docs) |
+-------------------------+
| Starlette |
| - Routing |
| - Middleware |
| - WebSockets |
| - Background tasks |
+-------------------------+
| Uvicorn |
| - ASGI web server |
| - uvloop + httptools |
+-------------------------+
FastAPI’s central idea is that Python type hints should serve not only as input for static analysis, but also as the framework’s basis for validating request data and generating API documentation.
When a developer declares item_id: int in a route, the same type information serves four purposes:
- Path parameter extraction: Automatically parse the corresponding parameter from the URL.
- Data conversion and validation: Automatically convert a request string to an integer and return a structured HTTP 422 error if it does not match the declared type.
- OpenAPI specification generation: Expose the parameter type in the OpenAPI JSON Schema, which drives the Swagger UI at
/docs. - Editor type inference: Enable real-time autocomplete and static type checking in VS Code and PyCharm.
From the outset, Sebastián Ramírez repeatedly tested how type hints worked in the mainstream editors used by roughly 80% of developers. FastAPI pursued more than server-side performance: it made a smooth editing and autocomplete experience a top priority.
An Eight-Year Timeline: From Microframework to Modern Toolchain
FastAPI’s version number remained at 0.x for years, but jumps between minor versions often brought major architectural changes. Its releases from 2018 to 2026 fall into three key phases:
| Version | Release date | Key change or milestone |
|---|---|---|
0.1.0 | 2018-12-08 | First public release |
0.93.0 | 2023-03-07 | Introduced the asynchronous lifespan context manager |
0.95.0 | 2023-03-18 | Added support for, and broadly recommended, the standard Annotated syntax for declaring dependencies |
0.100.0 | 2023-07-07 | Officially added Pydantic v2 support, beginning a long period of compatibility with both versions |
0.111.0 | 2024-05-03 | Introduced the official CLI: fastapi dev and fastapi run |
0.112.0 | 2024-08-02 | Slimmed down the core package and moved standard features to fastapi[standard] |
0.126.0 | 2025-12-20 | Officially ended Pydantic v1 support and required at least Pydantic 2.7.0 |
0.130.0 | 2026-02-22 | Shifted JSON serialization to Pydantic’s Rust engine, cutting CPU overhead |
0.135.0 | 2026-03-01 | Added native Server-Sent Events (SSE) support |
Phase One: A Watershed for Syntax and Compatibility in 2023
The year 2023 marked a turning point in how modern FastAPI applications were written. Within five months, the project introduced lifespan, the Annotated syntax for dependency injection, and Pydantic v2 support.
The earlier pattern, user: User = Depends(get_user), placed Depends in the parameter’s default-value position. When a unit test called the function directly, the parameter received a Depends object instead of actual user data, producing unexpected behavior. Static analysis tools could also misinterpret it.
Version 0.95.0 began recommending the Python standard library’s Annotated[User, Depends(get_user)], which puts the parameter type and Depends in one annotation and makes type definitions easier to reuse across routes.
Earlier that month, version 0.93.0 deprecated the separate @app.on_event("startup") and @app.on_event("shutdown") handlers in favor of an ASGI-based lifespan context manager. This made the lifecycle of database connection pools and global state clearer and easier to control.
Phase Two: The Developer Toolchain Takes Shape in 2024
As the ecosystem matured, FastAPI expanded its focus from the framework core to the full development experience.
The official CLI (fastapi dev and fastapi run) simplified Uvicorn’s formerly cumbersome startup options. The project also bundled commonly used optional packages into fastapi[standard], giving developers more flexibility to choose between a minimal installation and an out-of-the-box setup.
Phase Three: Retiring Legacy Support and Improving Performance in 2025–2026
After that two-and-a-half-year compatibility transition, FastAPI ended support for Pydantic v1 and Python 3.8/3.9 in late 2025.
With those constraints removed, version 0.130.0 made fuller use of Pydantic’s underlying Rust engine, pydantic-core. Responses that declare a response model or a Pydantic return type now skip the previous Python-level, field-by-field conversion through jsonable_encoder and are serialized directly to JSON in Rust, substantially reducing serialization latency and CPU overhead for high-throughput APIs. The FastAPI release notes document this history in detail.
Confronting a Language Standard: The PEP 563 Crisis and the Turn to PEP 649
One of the most consequential events in FastAPI’s history was its role, alongside Pydantic, in changing the direction of a Python language feature.
The Crisis: The Threat of Stringified Annotations
PEP 563, proposed in 2017, aimed to address circular type references and module import performance by postponing the evaluation of annotations. Its approach was to turn all annotations into plain strings at compile time—the behavior enabled by from __future__ import annotations.
Stringified annotations had little effect on purely static analysis tools such as mypy. But Pydantic and FastAPI need to resolve actual type objects at runtime. For them, stringification meant relying on costly and fragile dynamic eval() calls. Those calls often failed when local scopes, closure variables, or nested type definitions were involved.
The plan to make all annotations strings by default in Python 3.10 would, if implemented, have severely disrupted the modern web ecosystem that reads actual types at runtime.
Python 3.10 Plan (PEP 563)
+-------------------------------+
| Stringified annotations |
| def f(x: int) -> str: |
| annotations = {'x': 'int'} |
+-------------------------------+
|
| Breaks runtime reflection
v
❌ Broke Pydantic & FastAPI
Community Resolution (PEP 649 / 749)
+-------------------------------+
| Deferred evaluation |
| - Via descriptors (functions) |
| - Computed only when read |
+-------------------------------+
|
| Preserves real type objects
v
✅ Adopted in Python 3.14 (2025)
Community Negotiation and the Steering Council’s Decision
On April 15, 2021, Pydantic creator Samuel Colvin published an urgent appeal on GitHub:
“In short, Pydantic does not work well with postponed annotations, and it may never work well with them.”
The issue quickly sparked broad discussion across the developer community and on Hacker News.
Five days later, on April 20, Python Steering Council member Thomas Wouters announced on the python-dev mailing list that the decision to make PEP 563 the default in Python 3.10 had been withdrawn:
“Our decision at this point is that we cannot afford the compatibility breakage risk posed by PEP 563.”
The community then turned toward PEP 649, proposed by Larry Hastings, with implementation details later refined by PEP 749. Under this approach, annotation evaluation is wrapped in a lazy function and happens only when code explicitly reads the annotations. It avoids circular-reference problems while preserving access to actual type objects at runtime.
After years of discussion, the matter was settled in Python 3.14, released in October 2025. PEP 649 became part of the language standard, while PEP 563 was officially superseded by PEP 649/749, its proposals having “never become the default behavior.”
The reversal amounted to official recognition that runtime type reflection is no longer a fringe use case, but foundational to modern Python application development.
NOTE
Further reading: The Evolution of Python Type Hints: A 20-Year Journey to Maturity
Migrating to Pydantic v2: The Benefits and Costs of a Composed Architecture
FastAPI chose to delegate data validation entirely to Pydantic. This kept the framework’s code structure lean, but it also meant that FastAPI’s evolution was closely tied to an external project.
A Rust Rewrite and the Compatibility Challenge
Pydantic v2 was officially released in June 2023. To maximize performance, Pydantic rewrote its core validation logic in Rust as the separate pydantic-core package. The result was a substantial speed improvement, accompanied by breaking changes to its underlying APIs.
FastAPI released 0.100.0 with Pydantic v2 support within a week of Pydantic v2’s release. To protect its large base of downstream enterprise applications, however, Sebastián Ramírez opted for a two-and-a-half-year transition of dual support.
The transition proceeded in three steps: version 0.100.0 supported both v1 and v2 in July 2023; version 0.119.0 allowed old and new models to coexist in one project in October 2025; and versions 0.126.0–0.128.0 finally retired v1 and its compatibility layer at the end of 2025. This gave the community and third-party packages time to migrate.
The experience illustrates a central trade-off of a composed architecture: using an existing component does not eliminate maintenance costs. A framework must absorb the compatibility costs of a major upgrade to a core dependency on behalf of its downstream users.
⭐️Container Deployment Philosophy: The Cloud-Native Shift to One Process per Container
For operations and DevOps engineers, the evolution of FastAPI’s official deployment advice reflects a broader change in thinking about containerized architecture over the past several years.
Phase 1: Multi-Process in Container
+------------------------------+
| Single Pod |
| +--------------------------+ |
| | Gunicorn (master) | |
| +--------------------------+ |
| | | |
| v v |
| +----------+ +----------+ |
| | Worker | | Worker | |
| +----------+ +----------+ |
+------------------------------+
|
v
Phase 2: Cloud Native (K8s)
+------------------------------+
| Kubernetes |
| +--------------------------+ |
| | HPA scaling | |
| +--------------------------+ |
| | | | |
| v v v |
| +------+ +------+ +------+ |
| | Pod | | Pod | | Pod | |
| | (1P) | | (1P) | | (1P) | |
| +------+ +------+ +------+ |
+------------------------------+
Managing Uvicorn Workers with Gunicorn
In FastAPI’s early days, Uvicorn did not yet have a mature mechanism for restarting crashed processes. The official recommendation was to use the tiangolo/uvicorn-gunicorn-fastapi image, with a Gunicorn master process monitoring and managing multiple Uvicorn worker processes.
Deprecating the Multiprocess Image: One Process per Container in Clusters
As Uvicorn became more stable and Kubernetes became a mainstream deployment platform, FastAPI officially deprecated the Gunicorn image. Its deployment guide reframed the principle for containerized deployments:
“If you use a container orchestration system such as Kubernetes, handle replica scaling at the cluster level and run just one Uvicorn process in each container.”
This principle assumes a cluster. For a deployment using Docker Compose on a single server, without cluster-level replicas and load balancing, the official documentation still shows how to run multiple worker processes inside one container with --workers.
Adding another process manager inside a container makes health checking and resource allocation more complex. When the cluster manages replicas and each container runs one process, these three operational concerns map more directly to a Pod:
| Operational concern | Earlier multiprocess container (Gunicorn + Uvicorn) | Modern cloud-native architecture (one process per container) |
|---|---|---|
| Health checks | Can enter a gray area where the master is alive but a worker has crashed | Probe results correspond directly to the single process; kubelet restarts the container when it fails |
| Resource isolation | Multiple workers share a container, making memory use hard to estimate and increasing the risk of OOM errors | Requests and limits correspond more precisely to one process |
| Scaling control | Requires manually calculating and adjusting the number of workers inside each container | An HPA automatically scales replicas at the cluster level according to load |
Integration with the Modern CLI
With fastapi dev and fastapi run, a modern Dockerfile needs just one line:
CMD ["fastapi", "run", "app/main.py", "--port", "80"]
FastAPI also added fastapi deploy in version 0.116.0, extending its deployment path to cloud hosting services.
Documentation as a Product: From Interactive Specifications to Agent Skills
FastAPI’s documentation is a big part of why developers understand it and get started so quickly. It is more than an API reference: it is a progressive, hands-on guide that also covers the fundamentals of Python’s type system and asynchronous programming.
Interactive Documentation Generated from API Declarations
By integrating OpenAPI with Swagger UI and ReDoc, FastAPI lets backend engineers debug APIs interactively at /docs as soon as the service starts, without maintaining separate API documentation. This substantially reduces the communication cost between frontend and backend teams and lets the API specification serve directly as input to client code generators.
Documentation Evolves for the AI Era
As the project expanded and AI-assisted development became more common, FastAPI’s documentation system underwent two notable changes:
- An automated LLM translation pipeline: In late 2025, FastAPI moved away from its traditional volunteer review process and adopted an automated LLM pipeline for multilingual translations, keeping documentation in 13 languages synchronized.
- Library Agent Skills: In early 2026, version
0.133.1introduced the “FastAPI Agent Skill,” packaging framework conventions and typing guidance into a standard skill file for AI coding assistants such as Claude and Copilot.
As AI increasingly assists with code generation, helping models accurately understand a framework and produce code that follows its best practices has become a new way for open-source projects to keep their ecosystems competitive.
Conclusion: Three Themes Across Eight Years of Evolution
FastAPI’s evolution from its birth in 2018 through 2026 follows three clear themes:
- Embracing and advancing Python standards: FastAPI moved from framework-specific patterns toward the standard
Annotatedsyntax andlifespan, and even helped push PEP 649 to its final adoption. It has become an influential force in shaping modern Python language features. - Balancing the trade-offs of a composed architecture: Building on Starlette and Pydantic enabled rapid innovation, while major ecosystem upgrades required patience and sustained compatibility work.
- Growing from a framework into a full development platform: What began as a routing and validation framework expanded into a modern toolchain spanning a CLI, cloud deployment, and AI Agent Skills.
As FastAPI outgrows its microframework roots and moves into commercial hosting services, what new tensions and choices will arise around open-source governance, commercialization, competing approaches to performance, and its place in the AI era?
Part 2 explores these questions.