mrkeyoor.com_
Sat 19 Sept 15:53 UTC
PyPIWeb Backendupdated 19 Sept 2026

uvicorn review

Uvicorn 0.52.4 is an ASGI server that turns HTTP/1.1 and WebSocket connections into events for applications built with FastAPI, Starlette, async Django, or another ASGI framework. It handles lifespan startup and shutdown, process workers, development reloads, proxy headers, sockets, TLS, access logs, and connection limits. The base package uses Python's asyncio and h11; the standard extra can add uvloop, httptools, watchfiles, WebSocket support, dotenv loading, and YAML logging config. Version 0.52.4 fixes duplicate Date headers on accepted WebSocket handshakes using websockets-sansio. The new zttp HTTP parser remains explicitly experimental and should stay out of production traffic.

Verdict

Uvicorn 0.52.4 installed in 0.4 seconds, occupied 2 MB across three packages, and returned zero audit findings in our sandbox, so it is a small default server for HTTP/1.1 ASGI applications. Choose another server for application-level HTTP/2 or Trio, and do not treat proxy trust or worker resource limits as framework defaults.

We installed it

Lab card: what happened when we installed uvicornScreenshot of uvicorn documentation
Install✓ · 0.4s3 packages on disk · 2 MB
Importimport uvicorn in 0.46s · pure Python · py.typed · requires Python >=3.10
Known vulns0(pip-audit)

Answers from our run

Does uvicorn install cleanly?

Yes. In a fresh container with an empty cache, pip install uvicorn finished in 0.4s, leaving 3 packages and 2 MB on disk. pip-audit reported no known vulnerabilities.

What does uvicorn need to run?

Python >=3.10, and nothing compiled: it is pure Python. In our run import uvicorn succeeded in 0.46s, and the package ships py.typed for type checkers.

uvicorn or hypercorn: which should you use?

hypercorn: Use it when HTTP/2, HTTP/3, or Trio support belongs in the application server. Uvicorn 0.52.4 installed in 0.4 seconds, occupied 2 MB across three packages, and returned zero audit findings in our sandbox, so it is a small default server for HTTP/1.1 ASGI applications.

When should you not use uvicorn?

HTTP/2 or HTTP/3 is required at the application server; Uvicorn's documented protocol support is HTTP/1.1 and WebSockets

API stability4/5The `module:app` import string, `uvicorn.run()`, ASGI lifecycle, and main CLI controls have stayed familiar across releases. Deployment details still move before 1.0: the in-package Gunicorn worker is deprecated, websockets-sansio became the automatic WebSocket choice, zttp arrived as an experimental HTTP option, and new worker health and recycling controls have appeared. Pin the version and exercise the exact startup command, signals, and protocol implementation used in production.
Docs5/5uvicorn.dev has specific pages for settings, deployment, Docker, server behavior, ASGI concepts, WebSockets, lifespan, release notes, and protocol implementation. The settings reference distinguishes `--env-file` from `UVICORN_*`, documents trusted forwarding sources, and explains each resource limit. The server-behavior page also states that concurrency overflow receives an immediate 503 rather than waiting in the backlog, a detail many deployment summaries miss.
Maintenance5/5Version 0.52.4 was published on 2026-08-19, and the repository was pushed on 2026-08-24. GitHub reports 10,927 stars, 83 open issues and pull requests, and no archive flag. The 0.52.x series quickly followed the experimental zttp addition with parser and WebSocket corrections. That pace shows active ownership, while the recent protocol churn makes a pinned canary test more useful than assuming every patch is operationally invisible.
Ecosystem5/5The supplied registry count is 153,141,769 weekly downloads. FastAPI and Starlette examples commonly use Uvicorn's import-string command, and ASGI keeps the same application portable to Hypercorn, Daphne, or Granian. Reverse proxies, container platforms, system process managers, and the external `uvicorn-worker` package understand its deployment shape. Uvicorn remains a server layer, so authentication, routing, validation, and application observability come from the framework and surrounding stack.

Discussed on

  1. hnUvicorn: The lightning-fast ASGI server9 points
  2. hnRestarting uvicorn Workers with the SIGHUP Signal8 points

Use it if

  • A FastAPI, Starlette, or other ASGI application needs a direct HTTP/1.1 and WebSocket server
  • A container should run one bounded server process with lifespan hooks and graceful termination
  • A reverse proxy will forward to a loopback port or Unix socket with a known trust boundary
  • Development needs file reload while production needs separate worker processes
Skip it if

Setup reality

We installed Uvicorn 0.52.4 in a clean Python 3.12 container in 0.4 seconds. Three packages used 2 MB on disk, and pip-audit found zero known vulnerabilities. The measured metadata counted 9 direct dependencies, required Python 3.10 or newer, described a pure-Python package, included py.typed, and supplied no usable license value. import uvicorn completed in 0.46 seconds. The 3-package base install uses h11 and does not include all components from uvicorn[standard].

No credentials or config file are required. --env-file loads variables for the ASGI application; it does not read UVICORN_* server settings from that file. Pass server options on the CLI, to uvicorn.run(), or through the actual process environment. Reload mode and worker mode are mutually exclusive. If code enables either one, keep uvicorn.run() under the if __name__ == "__main__" guard and pass the application as an import string.

A reverse proxy changes Uvicorn's view of the client address and URL scheme. --proxy-headers only accepts forwarded values from --forwarded-allow-ips, whose documented default is loopback. Set the proxy IP, network, or Unix socket path explicitly; * trusts every peer. Configure --root-path when the proxy publishes the application below a prefix. Four workers also mean four application startups, four memory spaces, and four sets of database pools or in-process caches.

--limit-concurrency sends an immediate 503 after the limit is reached; it does not put excess requests in the socket backlog. Idle keep-alive connections count toward that limit. Set request recycling and graceful-shutdown timeouts around the application's resource behavior, then test SIGTERM with live requests. Version 0.52.4 contains several recent WebSocket handshake and close-path fixes. Keep --http zttp in experiments because the 0.52 release notes tell operators not to send it production traffic yet.

Patterns

Reload a local application on file changes run-development

uvicorn main:app --host 127.0.0.1 --port 8000 --reload

`--reload` and `--workers` are mutually exclusive. Without watchfiles, reload checks Python file modification times and cannot use the full include and exclude behavior.

Start multiple production workers run-workers

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

Four workers are four processes with separate startup hooks, caches, and connection pools. Calculate downstream limits per process.

Start from Python without recursive workers run-programmatically

import uvicorn

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

Reload or workers require the main guard and an import string. Passing an application object only works without multiprocessing and reload.

Call a factory to create the ASGI app load-app-factory

# main.py
def create_app():
    from fastapi import FastAPI
    app = FastAPI()
    return app

# shell
uvicorn main:create_app --factory

`--factory` expects a zero-argument callable that returns an ASGI application. Each worker invokes the factory in its own process.

Use the external Gunicorn worker package run-with-gunicorn

pip install gunicorn uvicorn-worker
gunicorn main:app \
  --workers 4 \
  --worker-class uvicorn_worker.UvicornWorker \
  --bind 0.0.0.0:8000

Uvicorn's bundled `uvicorn.workers` module is deprecated. The separately installed `uvicorn-worker` package provides `uvicorn_worker.UvicornWorker`.

Accept forwarded headers from a known proxy trust-reverse-proxy

uvicorn main:app \
  --host 127.0.0.1 \
  --port 8000 \
  --proxy-headers \
  --forwarded-allow-ips=10.20.0.0/16 \
  --root-path=/api

The literal `*` trusts forwarding headers from every peer. Supply the proxy network or socket path so clients cannot choose their reported IP or scheme.

Serve a reverse proxy over a Unix socket bind-unix-socket

uvicorn main:app --uds /run/example/uvicorn.sock

# nginx location block:
# proxy_pass http://unix:/run/example/uvicorn.sock;

The proxy user needs access to the socket and its parent directory. Remove stale socket files through the service lifecycle if startup cannot replace them.

Refuse excess work at a known limit cap-concurrency

uvicorn main:app \
  --limit-concurrency 200 \
  --backlog 1024 \
  --timeout-keep-alive 5

`--limit-concurrency` returns 503 immediately when reached. The backlog is the OS accept queue and does not hold requests rejected by the application-level limit.

Bound request count and shutdown time recycle-workers

uvicorn main:app \
  --workers 4 \
  --limit-max-requests 10000 \
  --limit-max-requests-jitter 1000 \
  --timeout-graceful-shutdown 30

Jitter staggers worker recycling. After the graceful timeout, Uvicorn begins terminating requests that have not completed.

Load application variables from a file load-environment

# .env.application
DATABASE_URL=postgresql://db/app
FEATURE_X=1

# shell
UVICORN_PORT=9000 uvicorn main:app --env-file .env.application

`--env-file` configures the ASGI application. Put `UVICORN_PORT` in the process environment or CLI because Uvicorn does not read its own settings from that file.

Use a logging configuration file configure-logging

uvicorn main:app --log-config logging.yaml

# Or disable access records explicitly:
uvicorn main:app --no-access-log --log-level warning

YAML log configuration needs PyYAML, which the standard extra installs. Access records can expose paths and query strings, so define redaction and retention outside Uvicorn defaults.

Pin the current WebSocket implementation select-websocket

pip install 'uvicorn[standard]'
uvicorn main:app --ws websockets-sansio

The automatic WebSocket choice uses websockets-sansio when the `websockets` dependency is installed. Version 0.52.4 fixes its duplicate Date header on accepted handshakes.

Alternatives

PackageRegistryPick it when
hypercornPyPIUse it when HTTP/2, HTTP/3, or Trio support belongs in the application server.
daphnePyPIUse it for Django Channels deployments already built around Daphne and its HTTP/2 support.
granianPyPIUse it when a Rust-based ASGI server and HTTP/2 are worth a separate production benchmark.
mangumPyPIUse it to adapt an ASGI application to AWS Lambda and API Gateway without opening a listener.

More web backend guides

urllib3 · requests · ws · anyio · undici · httpx · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.