FastAPI is a Python API framework that uses type annotations. Request declarations define input validation and OpenAPI documentation. Declared response models also validate and filter output. Async handlers can let other requests progress while awaiting a database or external service.
Key takeaways:
FastAPI combines type-based request validation with generated OpenAPI documentation; response models define and check output.
Async handlers can overlap waits on databases or external APIs when their clients support async I/O. CPU-heavy work needs a separate execution strategy.
FastAPI requires Pydantic v2. Migrate v1 models before upgrading.
Django offers an integrated application stack; Flask and Litestar offer different conventions for handlers and concurrency.
Vercel detects standard FastAPI layouts and supports Python 3.12, 3.13, and 3.14.
Copy link to headingWhat is FastAPI?
FastAPI is an open-source Python web framework for building APIs with standard type hints. It supports Python 3.10 and newer and uses the MIT license.
Sebastián Ramírez created FastAPI after building APIs for machine learning and distributed systems. He wanted less duplication and better editor support.
FastAPI depends on Starlette for routing, WebSockets, sessions, and test utilities. Pydantic v2 validates and serializes data and generates the JSON Schema definitions used in FastAPI's OpenAPI document.
Copy link to headingHow does FastAPI differ from traditional frameworks?
Web Server Gateway Interface (WSGI) and Asynchronous Server Gateway Interface (ASGI) define how Python applications communicate with web servers. FastAPI uses ASGI to support async request handling. Django supports both interfaces; Flask normally runs as a WSGI application.
The table compares common synchronous or threaded WSGI deployments with an ASGI deployment of FastAPI. Server configuration and the libraries used by handlers still determine how much concurrent work each application can serve.
The concurrency benefit appears when a handler awaits a database query or external API call through an async client. During that wait, the event loop can run other requests. Blocking calls need the separate handling described below.
Copy link to headingWhy is FastAPI important for API development?
Shared route and model declarations support several parts of API development:
Editors such as VS Code and PyCharm use annotations to offer completion and static type checks as you write handlers.
FastAPI validates declared request fields and returns structured 422 errors by default when validation fails.
OpenAPI describes the declared request and response schemas. Swagger UI at
/docsand ReDoc at/redocmake that contract available to API consumers.OpenAPI generators create typed clients for web and mobile apps.
Copy link to headingCore FastAPI features
FastAPI connects its request handlers to an ASGI server through Starlette. Route declarations describe the expected data, Pydantic validates it, and the generated OpenAPI schema documents the API contract.
Copy link to headingAsync request handling with ASGI
An async def handler can yield the event loop while awaiting an async operation, allowing other requests to progress. FastAPI runs plain def route handlers and dependencies in a thread pool. Synchronous helpers called directly from an async handler stay on the event-loop thread unless you explicitly offload them.
This helps with waits on async database clients or external APIs. CPU-heavy code running on the event-loop thread blocks other work there until it yields or finishes; changing its declaration to async def does not make that computation parallel.
Copy link to headingRequest declarations with type hints
FastAPI combines annotations with defaults and parameter declarations to describe a request. For example, q: str | None = None makes the query parameter optional by providing a default. The | None annotation permits a Python value of None; that annotation alone does not make the request parameter optional.
Field constraints can enforce a minimum price or maximum string length. Rules such as whether a customer may buy an item still belong in application logic. Declaring a body as a bare dict retains object validation but gives FastAPI no named fields to validate or document. Use a Pydantic model for known fields.
Copy link to headingData validation with Pydantic v2
Pydantic validates incoming values and can convert compatible input into the declared Python types. For example, a numeric string may become a number unless strict validation is enabled. BaseModel subclasses define body fields, defaults, and constraints; FastAPI also accepts lists and dictionaries.
For output, a response_model or supported return annotation defines the data FastAPI validates and serializes before sending the response.
Pydantic v2 uses a Rust validation core. In its 2022 announcement benchmarks, the Pydantic team reported validation between 4 and 50 times faster than v1.9.1. Those results measure validation, not end-to-end FastAPI throughput.
Copy link to headingInteractive docs with OpenAPI
FastAPI generates an OpenAPI 3.1 schema for HTTP routes included in the API schema. By default, /openapi.json exposes that document and Swagger UI at /docs lets teams send requests from the browser. ReDoc at /redoc provides a reference view. You can change or disable these URLs and exclude individual HTTP routes from the schema.
Route-level metadata makes those docs easier for consumer teams to use. Tags group related operations, summaries label each one, and the JSON Schema examples field, which replaces the deprecated example, adds sample payloads.
Copy link to headingA minimal FastAPI example
The smallest useful FastAPI app fits in one file. This one defines three routes: a home route that returns a fixed message, a route that reads an item ID from the URL and an optional search term from the query string, and a route that accepts a JSON item and checks it against a model.
Save the application as main.py:
from fastapi import FastAPIfrom pydantic import BaseModel
app = FastAPI()
class Item(BaseModel): name: str price: float is_offer: bool | None = None
@app.get("/")def read_root(): return {"Hello": "World"}
@app.get("/items/{item_id}")def read_item(item_id: int, q: str | None = None): return {"item_id": item_id, "q": q}
@app.put("/items/{item_id}")def update_item(item_id: int, item: Item): return {"item_name": item.name, "item_id": item_id}In an activated virtual environment, install FastAPI with its standard extras, which include the fastapi command and Uvicorn. Start the development server from the folder containing main.py:
pip install "fastapi[standard]"fastapi dev main.pyThe development server reloads after changes and exposes interactive docs at http://127.0.0.1:8000/docs. Try a non-numeric item ID or a PUT body without price to trigger a 422 validation error before the handler runs.
For a uv-managed project, use uv add "fastapi[standard]" and uv run fastapi dev main.py. When managing your own production server, use fastapi run main.py instead of the development command.
Copy link to heading5 FastAPI best practices for production teams
Concurrent traffic exposes failure modes the quickstart doesn't. These five practices cover the minimum discipline as the app grows.
Copy link to headingMatch handlers to library behavior
Calling a blocking driver such as psycopg2 from an async def handler stalls its event loop. Use an async client such as asyncpg, or put synchronous I/O in a plain def handler that FastAPI runs in its thread pool.
Thread capacity is shared and limited, so test concurrent traffic with the libraries your app uses. For heavy CPU work, consider a separate process or worker instead of occupying request-handling capacity.
Copy link to headingValidate responses explicitly
Request models do not define the response contract. Declare a response_model or a supported return annotation to validate returned data and filter fields before serialization. Test invalid returns as well as successful ones; a response that fails validation should produce a server error.
Returning a Response object directly bypasses that model processing, so validate and serialize its content yourself.
Copy link to headingSeparate dependencies from route logic
As routes accumulate, handlers start duplicating authentication, database-session code, and shared validation, and one policy ends up with several implementations. Declaring each as a dependency with Depends() keeps it in one place, with yield and try/finally handling cleanup.
Copy link to headingMigrate fully to Pydantic v2
Pydantic v2 deprecates @validator and parse_raw in favor of @field_validator and model_validate_json. Update these calls in older code.
For ORM objects, replace from_orm with model_validate and set from_attributes=True in the model configuration. Replace __root__ models with RootModel. Complete the migration before adopting Python 3.14, which does not support Pydantic v1.
Copy link to headingTest the generated contract
Vague route declarations produce vague documentation, and /docs may become the only contract consumer teams have. Inspecting /openapi.json after each schema change and testing response schemas catches a renamed field before a mobile team does.
Copy link to headingWhen FastAPI is the right choice
FastAPI fits teams that want typed API contracts and generated documentation. Its async support is also useful when handlers spend time awaiting other systems. These benefits apply differently to machine learning (ML) model-serving APIs, large language model (LLM) integrations, microservices, and full-stack products.
Copy link to headingAPIs that serve ML models
Typed request and response models define a prediction API's inputs and outputs. With a remote inference service, an async client can await the result while other requests progress. Local inference needs its own CPU or GPU capacity plan because async handling does not parallelize model computation.
For models loaded within the application, use a lifespan handler to initialize them at startup and reuse them across requests. On Vercel, each new function instance initializes its own application resources.
Copy link to headingAPIs that wrap LLM calls
LLM-backed APIs can await several model calls concurrently when they use an async client. Validate the provider response with a Pydantic model before using it in application logic, and handle validation failures there.
Your route response model checks what your API returns; it does not automatically validate intermediate model output or establish that a generated answer is correct.
Copy link to headingMicroservices that share typed contracts
Teams running several services choose FastAPI when keeping contracts in sync is the hard part. Each service generates its /openapi.json from its own code, so downstream services can build typed clients from it and catch a breaking change in continuous integration (CI).
Copy link to headingFull-stack products that ship from one repository
When a Python API and JavaScript frontend share a repository, teams can review contract changes alongside the UI code that consumes them. FastAPI's generated OpenAPI schema can support client generation and compatibility checks.
Delphi's Vercel case study illustrates the deployment side: after moving its Python backend to Vercel, the company reported more than 100 daily production deploys with 10 engineers and no dedicated infrastructure role.
Copy link to headingWhen to choose a FastAPI alternative
Choose among these frameworks based on the application components you need and the libraries your handlers call.
Copy link to headingUse Django for complete applications
Django fits applications that need an integrated admin, object-relational mapper (ORM), migrations, and authentication. Those components can reduce the integration work for products centered on database-backed workflows. FastAPI provides API and security utilities but leaves you to choose and connect the rest of that application stack.
Copy link to headingUse Django Ninja inside Django
An existing Django application can add Django Ninja to expose a typed API alongside its views while continuing to use the ORM, admin, and authentication. For a new project, choose it when you also want those Django components.
Copy link to headingUse Flask with synchronous libraries
Flask suits teams that prefer its conventions and already use synchronous libraries. Under a conventional WSGI deployment, each active request occupies a worker even if the view uses async def. The server's worker configuration determines concurrency, so size and test that deployment for the traffic you expect.
Copy link to headingUse Litestar for explicit concurrency
Litestar asks you to declare how synchronous handlers should run. Set sync_to_thread=True for blocking work, or False when the handler can run without blocking the event loop. Omitting the setting on a synchronous handler triggers a warning; Litestar does not inspect the code to guarantee that it is nonblocking.
Copy link to headingHow Vercel runs FastAPI
Vercel's Python runtime deploys FastAPI as Vercel Functions and uses the same application object you run locally. Dependencies can come from pyproject.toml, requirements.txt, or a Pipfile paired with Pipfile.lock.
New projects use Fluid compute by default. For an existing project, check whether it is enabled before deploying.
Copy link to headingDeploy with zero configuration
The FastAPI preset detects an app instance in standard entrypoints such as main.py, app.py, and index.py, including those filenames under src/ or app/. These layouts do not require an /api directory or a vercel.json rewrite configuration.
Custom layouts set the entrypoint in pyproject.toml:
[tool.vercel]entrypoint = "backend.server:app"Default layouts don't need the setting, and existing projects can keep [project.scripts] or the /api layout.
Copy link to headingSet supported Python versions
Vercel supports Python 3.12, 3.13, and 3.14, with 3.12 as the default. To select a minor version, use the appropriate version file: for example, put 3.13 in .python-version. In pyproject.toml, declare the compatible range under [project].requires-python. Pipenv projects can provide the version through their generated Pipfile.lock.
FastAPI supports Python 3.10 and newer, but Vercel's available runtime versions are a narrower set. Run the test suite against the version you select for deployment.
Copy link to headingSize functions for long-running requests
On Fluid compute, Hobby functions run for up to 300 seconds; Pro and Enterprise support up to 800 seconds.
The extended-duration beta allows up to 1,800 seconds on supported Python runtimes through per-function configuration. For FastAPI, configure the resolved entrypoint file in vercel.json. Secure Compute and Static IPs do not support durations above 800 seconds during the beta.
The standard Python bundle limit is 500 MB uncompressed. Large Functions support up to 5 GB in public beta with Fluid compute and Active CPU enabled. Eligible new projects have support by default; existing projects can opt in. The beta excludes Secure Compute and Static IPs.
Active CPU billing excludes time spent waiting for external services. Provisioned memory remains billable until the last in-flight request completes, including time spent awaiting an LLM response.
Copy link to headingCombine frontend and backend services
Vercel Services, currently in beta, can deploy a JavaScript frontend and FastAPI backend as one project with a shared preview deployment.
Declare the services in vercel.json, then add top-level rewrites to expose the paths you need, such as / for the frontend and /api for the backend. Services remain internal unless a rewrite exposes them.
Copy link to headingHandle WebSocket connections
WebSocket support is generally available on Fluid compute and works with FastAPI's standard WebSocket routes. Connections close at the function's configured maximum duration, so clients need reconnect logic and a way to restore any required session state.
Copy link to headingDeploy a FastAPI project
Create a Vercel project and connect the repository containing your FastAPI app, or choose a starting point from the template gallery. Before deploying, confirm the entrypoint, dependencies, and Python version match the app you tested locally.
Copy link to headingFrequently asked questions about FastAPI
Copy link to headingWhat Python version does FastAPI require?
FastAPI supports Python 3.10 and newer. Version 0.125.0 dropped Python 3.8 in December 2025, and 0.129.0 dropped Python 3.9 in February 2026.
Copy link to headingDoes FastAPI work with Pydantic v1?
Current FastAPI releases require Pydantic v2. Temporary support for pydantic.v1 models existed in FastAPI 0.119.0 through 0.127.x and was removed in 0.128.0.
This path requires Python 3.13 or earlier because Pydantic v1 does not support Python 3.14. Follow the migration guide and test your application before upgrading.
Copy link to headingIs FastAPI production-ready?
Yes. Microsoft, Uber, and Netflix appear among FastAPI's published adopters. Readiness for a given API depends more on its handler, testing, and deployment choices than on the framework itself.
Copy link to headingDoes FastAPI need a separate server in production?
On a traditional host, yes. fastapi run starts Uvicorn, the ASGI server included with the fastapi[standard] extra. On Vercel, the Python runtime serves the app object directly, with no server process to configure.