2025, Nov 04 15:00
Do modern FastAPI deployments still need Gunicorn, or is Uvicorn's built-in supervisor enough?
Do you still need Gunicorn for FastAPI? Compare Uvicorn's supervisor (--workers) vs fastapi run, and when systemd socket activation or sd_notify tips choice.
Gunicorn plus Uvicorn used to be the go-to stack for running FastAPI in production. That guidance has shifted. Uvicorn gained a built-in multi-process supervisor, FastAPI adjusted its tooling, and the well-known Docker image that bundled Gunicorn was deprecated. If you’re wondering whether you still need Gunicorn and whether commands like fastapi run and gunicorn are equivalent, this guide walks through the practical answer with just the facts you need.
Minimal example that mirrors the question
Assume a small FastAPI app living in server.py. The only purpose here is to show how it’s launched, not to demonstrate application logic.
# server.py
from fastapi import FastAPI
svc = FastAPI()
@svc.get("/health")
async def healthcheck():
return {"ok": True}
The two ways you might try to run it with multiple workers look like this:
# Using the FastAPI CLI, which wraps Uvicorn
fastapi run --workers 4 server.py
# Using Gunicorn with the Uvicorn worker class
gunicorn server:svc -w 4 -k uvicorn.workers.UvicornWorker
What changed and why it matters
Since Uvicorn 0.30 (May 2024), a built-in supervisor handles multi-process workloads directly. It supports launching multiple worker processes with --workers, restarting crashed workers automatically, and request limits via --limit-max-requests for leak mitigation. Shortly afterward, the tiangolo/uvicorn-gunicorn-fastapi Docker image was deprecated with the rationale:
Now that Uvicorn supports managing workers with --workers, including restarting dead ones, there's no need for Gunicorn.Starting with FastAPI 0.110, fastapi run is a thin wrapper around this new Uvicorn supervisor. Upstream Uvicorn no longer recommends pairing with Gunicorn. In short, the default advice has become plain Uvicorn or fastapi run for most cases.
Does modern FastAPI need Gunicorn?
No. With Uvicorn 0.30 and newer, you don’t need Gunicorn to manage workers. The Uvicorn supervisor covers the core production features that motivated the combined stack for a long time.
Are fastapi run and gunicorn equivalent?
No. They are different implementations even if they can both launch multiple workers for the same app. The FastAPI CLI delegates to Uvicorn’s built-in supervisor, while Gunicorn uses its own master process and the uvicorn.workers.UvicornWorker class. One practical niche where Gunicorn still stands out is systemd integration. It supports inheriting listen sockets from systemd .socket units and implements sd_notify when started as a Type=notify service. If those features matter in your environment, Gunicorn remains relevant.
Recommended way to run FastAPI today
For most deployments, use Uvicorn directly or the FastAPI CLI. Both rely on Uvicorn’s supervisor introduced in 0.30 and provide multi-process execution with automatic worker restarts.
# Uvicorn directly
uvicorn server:svc --workers 4
# FastAPI CLI (thin wrapper around Uvicorn's supervisor)
fastapi run --workers 4 server.py
If you have a specific operational requirement for systemd socket activation or sd_notify, you can opt for Gunicorn with the Uvicorn worker class instead.
Why you should care
The operational baseline has changed. You can simplify your stack by dropping an extra process manager when you don’t need its unique features. The deprecation of the tiangolo/uvicorn-gunicorn-fastapi Docker image and FastAPI’s alignment with Uvicorn’s supervisor signal a clear direction for typical production setups, while still leaving room for environments that rely on systemd-specific capabilities.
Takeaways
Modern FastAPI deployments generally do not need Gunicorn, because Uvicorn 0.30 added a supervisor with --workers, auto-restart, and request-limiting. fastapi run uses that same supervisor, so it’s a practical default. The Gunicorn invocation with uvicorn.workers.UvicornWorker is not identical under the hood, and it can still be a fit if you require systemd features like socket activation and sd_notify. Choose the simpler path when it meets your needs, and keep Gunicorn in your toolbox for the cases where its systemd integration is the deciding factor.
The article is based on a question from StackOverflow by Abionics and an answer by Jack Kinderly.