mrkeyoor.com_
Wed 05 Aug 05:06 UTC
PyPIWeb Backendupdated 05 Aug 2026

uvicorn

ASGI web server for Python: the process that accepts sockets and speaks HTTP/1.1 and WebSockets on behalf of async frameworks like FastAPI, Starlette, and Django in ASGI mode. Installs as pure Python by default, while the [standard] extra swaps in uvloop and httptools for real speed and adds watchfiles for --reload. It is the de facto default server in every FastAPI tutorial and deployment guide.

Verdict

The default ASGI server for good reason: fast, simple, and everywhere. Accept the HTTP/1.1-only limit, install the [standard] extra, and pair it with a proxy or process manager for production.

API stability4/5The CLI and uvicorn.run() surface has been steady for years despite the 0.x version number; removals like the bundled gunicorn worker came with deprecation warnings first
Docs4/5uvicorn.dev covers settings, deployment, and server behavior concisely with a full release-notes page; deeper operational topics hand you off to external tools
Maintenance4/5Maintained by Kludex of the FastAPI/Starlette orbit under the encode lineage; regular releases, a push within the last week, and only 79 open issues and PRs
Ecosystem5/5160M weekly downloads and the assumed default in FastAPI docs and most ASGI deployment guides; enormous body of tutorials and container recipes

Use it if

  • You run FastAPI, Starlette, Litestar, or any ASGI app and want the community-default server
  • You need WebSocket support alongside plain HTTP in one process
  • You want a fast dev loop: --reload restarts the server on file changes via watchfiles
  • You deploy containerized services where 'uvicorn app:app --workers 4' behind a proxy is the whole story
Skip it if

Setup reality

pip install 'uvicorn[standard]' is the install you actually want: the bare package silently skips uvloop, httptools, websockets, and the --reload machinery, and people burn time wondering why reload does nothing. Configuration is CLI flags or uvicorn.run() kwargs, no config file. Behind a reverse proxy you must pass --proxy-headers and set --forwarded-allow-ips or client IPs and https detection come out wrong. The gunicorn worker class moved out of core into the separate uvicorn-worker package, which breaks older deployment recipes.

Patterns

Run a dev server with auto-reloadrun-dev-reload

uvicorn main:app --reload --port 8000

--reload requires watchfiles, which only ships with the [standard] extra; on the bare install the flag falls back to a slower stat-based watcher or fails.

Start the server from Pythonrun-programmatic

import uvicorn

if __name__ == "__main__":
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

Pass the app as an import string (not the object) or reload and workers cannot re-import it in child processes.

Run multiple worker processesmultiple-workers

uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4

--workers is incompatible with --reload; workers share the listening socket but there is no rolling restart of a running fleet.

Run under gunicorn for process managementgunicorn-process-manager

pip install gunicorn uvicorn-worker
gunicorn main:app -w 4 -k uvicorn_worker.UvicornWorker --bind 0.0.0.0:8000

The old uvicorn.workers.UvicornWorker class was deprecated out of uvicorn core; the class now lives in the separate uvicorn-worker package.

Trust proxy headers behind nginx or a load balancerbehind-reverse-proxy

uvicorn main:app --host 127.0.0.1 --port 8000 \
  --proxy-headers --forwarded-allow-ips='10.0.0.0/8'

Without --proxy-headers your app sees the proxy's IP and http scheme; forwarded-allow-ips must include the proxy address or the headers are ignored.

Serve TLS directlyhttps-tls

uvicorn main:app --host 0.0.0.0 --port 443 \
  --ssl-keyfile ./key.pem --ssl-certfile ./cert.pem

Fine for internal services; for public traffic most teams terminate TLS at a proxy and keep uvicorn on plain HTTP.

Listen on a Unix domain socketunix-socket

uvicorn main:app --uds /tmp/uvicorn.sock

# nginx side:
# proxy_pass http://unix:/tmp/uvicorn.sock;

Sockets avoid localhost port juggling with a same-host nginx, but check file permissions so the proxy user can connect.

Customize logginglogging-config

uvicorn main:app --log-level warning --no-access-log

# or full control via a dictConfig file:
uvicorn main:app --log-config logging.yaml

YAML log configs require PyYAML, which is included in the [standard] extra; JSON and .ini configs work on the bare install.

Load settings from an env fileenv-file

uvicorn main:app --env-file .env

--env-file needs python-dotenv (part of the [standard] extra) and only sets process env vars; your app still reads them itself.

Serve a raw ASGI app with no frameworkminimal-asgi-app

# example.py
async def app(scope, receive, send):
    assert scope['type'] == 'http'
    await send({'type': 'http.response.start', 'status': 200,
                'headers': [(b'content-type', b'text/plain')]})
    await send({'type': 'http.response.body', 'body': b'Hello, world!'})

# run: uvicorn example:app

Useful for understanding what FastAPI abstracts away; headers and bodies are bytes, not strings.

Alternatives

PackageRegistryPick it when
hypercornPyPIYou need HTTP/2 or want to run on trio instead of asyncio
daphnePyPIDjango Channels deployments, where it is the original ASGI server
granianPyPIA Rust-based server with HTTP/2 when raw throughput is the priority
gunicornPyPIWSGI apps, or as the process manager in front of uvicorn workers