What Is Uvicorn? The ASGI Server Behind FastAPI, Explained
What Uvicorn actually does, how it relates to FastAPI and Starlette, and when you'd reach for it instead of Gunicorn
If you’ve followed a FastAPI tutorial, you’ve run uvicorn main:app --reload without necessarily knowing what Uvicorn itself is doing. It’s not part of FastAPI — it’s the layer underneath it.
What Uvicorn actually is
Uvicorn is an ASGI server — a program that receives HTTP (and WebSocket) requests from the network and hands them off to your Python application code, then sends the response back. ASGI is the async successor to WSGI, the older synchronous standard that servers like Gunicorn were built for. Your FastAPI or Starlette app doesn’t talk to the network directly; it implements the ASGI interface, and Uvicorn is what actually opens the socket and speaks HTTP.
Where it fits: FastAPI vs Starlette vs Uvicorn
Think of it as three layers:
- Uvicorn — the server. Handles raw HTTP/WebSocket connections, protocol parsing, and calls your app.
- Starlette — the ASGI toolkit. Routing, middleware, request/response objects.
- FastAPI — built on top of Starlette, adding request validation, automatic docs, and dependency injection via Pydantic.
You could run a Starlette app directly on Uvicorn with no FastAPI involved at all — FastAPI is a layer of developer convenience on top of Starlette, not a replacement for either Starlette or Uvicorn.
When you’d reach for it directly
In development, uvicorn main:app --reload is the standard way to run any ASGI app locally. In production, Uvicorn is commonly run either standalone with multiple worker processes, or — more often for real deployments — managed by Gunicorn using Uvicorn’s worker class, which adds process management, graceful restarts, and worker health checks that Uvicorn alone doesn’t handle.
Uvicorn vs Gunicorn: not actually competitors
This is a common point of confusion. Gunicorn is a process manager built for WSGI apps; it doesn’t natively understand ASGI. Uvicorn provides a Gunicorn worker class specifically so you get Gunicorn’s process management with Uvicorn’s actual request handling — gunicorn -k uvicorn.workers.UvicornWorker main:app is the typical production pattern, not an either/or choice.
The bottom line
Uvicorn is the thing actually listening on a port and speaking HTTP for nearly every modern async Python web framework. You rarely need to think about it beyond the run command — but when a deployment issue turns out to be about worker counts, connection handling, or graceful shutdowns, it’s usually Uvicorn’s configuration you’re looking at, not FastAPI’s.