Library / SDK
Kludex/uvicorn avatar
Kludex/uvicorn

Uvicorn: the ASGI server that sits under FastAPI

An ASGI web server, for Python. 🦄

10,993 stars1,045 forksPythonBSD-3-Clause

At a glance

What is it?
Uvicorn is a Python ASGI server with HTTP/1.1, HTTP/2 and WebSocket support. It installs in one pip command, and its optional extras decide whether you get Cython-backed parsing or pure Python.
Who is it for?
Adopt Uvicorn if you run an ASGI framework and want a server whose protocol handling you can swap through extras. Skip it if you need Trio, or if you deploy to AWS Lambda, where the README points to Mangum instead.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap Uvicorn fills between async frameworks and the network

Python's older web frameworks were built on WSGI: one synchronous callable that takes a request and returns a response. The README states plainly what that model cannot do well, naming long-lived connections such as long-poll HTTP and WebSocket. An ASGI server sits below the framework and speaks the protocol, so the framework author does not have to write one. Uvicorn is that server for Python, and it is the piece that turns an async callable into something a client can connect to.

The audience follows from that. If you write FastAPI, Starlette, Django Channels or any other ASGI application, you need a server to host it, and Uvicorn is one of the options. If you write only synchronous WSGI code, Uvicorn is the wrong layer entirely. The README also notes that async concurrency helps with endpoints blocked on slow network I/O and with lightweight background tasks, which is the kind of workload where a synchronous worker per request costs you threads.

What happens between a socket and your ASGI callable

The application contract is visible in the quickstart. An app is an async callable taking scope, receive and send. It reads the scope to learn what kind of connection arrived, then pushes messages back through send. The example asserts scope['type'] == 'http' and emits two messages: an http.response.start carrying status 200 and a content-type header, then an http.response.body carrying the bytes. That is the whole interface. Everything else is the server's job.

The dependency list in pyproject.toml shows the default path. Core Uvicorn depends on click, h11 and typing_extensions for Python below 3.11. h11 is a pure Python HTTP/1.1 implementation, so a bare install parses HTTP in Python. The standard extra changes that: it pulls in httptools for HTTP parsing, uvloop for the event loop where the platform allows it, websockets for the WebSocket protocol, watchfiles for --reload, python-dotenv for --env-file and PyYAML for YAML log configuration. The README describes these as Cython-based dependencies where possible, and notes the uvloop marker excludes win32, cygwin and PyPy. So the same application runs on a different protocol implementation depending on which install you chose, without a code change.

Installing Uvicorn and running a first app

The README gives two install forms. The first is a minimal, pure Python install. The second adds the optional extras described above. Pick the second for anything beyond a local experiment, because it is what brings in httptools, uvloop and the WebSocket implementation.

bash
$ pip install 'uvicorn[standard]'

With that installed, create a file. The README uses example.py and an async callable named app, which is the same shape every ASGI framework produces.

python
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!',
    })

Start it by passing the module and the attribute, separated by a colon. Uvicorn imports example, finds app and serves it.

bash
$ uvicorn example:app

A request to the default address should return the body Hello, world! with a text/plain content type. The --reload flag, which the README ties to watchfiles in the standard extra, restarts the process when files change and is meant for development. The --env-file option, backed by python-dotenv in the same extra, loads environment variables from a file. Both flags depend on extras that a bare install does not include.

The trade-offs in the extras and the version floor

The split install is the main design decision to think about. A bare pip install uvicorn gives you h11 and a pure Python event loop, which is portable but leaves performance on the table. The standard extra is faster where it applies, but its markers mean the fast path is not uniform: uvloop is excluded on Windows, on cygwin and under PyPy, so a Windows deployment does not get the same event loop as a Linux one. Debugging a performance difference between environments starts with checking which extras actually resolved.

There is a second constraint that is easy to miss. pyproject.toml sets requires-python to >=3.10, and the classifiers list CPython 3.10 through 3.14 plus PyPy. If you are pinned to an older interpreter, this release line is not available to you, and no flag changes that. The project also classifies itself as Development Status 4 - Beta despite regular releases, which is a statement about API stability expectations rather than a warning about the code. Treat it as a signal that a minor release can change behaviour.

The README does not document rollback or downgrade steps, and it does not describe a built-in process manager. Running multiple workers or supervising the process is left to you or to a separate tool, which is exactly the gap Gunicorn fills.

Uvicorn against Daphne, Hypercorn and Granian

The README lists the alternatives itself, which is unusually candid. Daphne was the first ASGI server, built to power Django Channels, and the README says it runs widely in production with HTTP/1.1, HTTP/2 and WebSockets. Hypercorn began inside the Quart framework before splitting out, and its distinguishing feature is support for Trio as an alternative to asyncio. That is a real difference in approach: if your application is written against Trio, Uvicorn is not the tool, because nothing in the dependency list or the README offers a Trio backend.

Granian takes a different route again. It is described as an ASGI compatible Rust HTTP server with HTTP/2, TLS and WebSockets, so the protocol layer is not Python at all. That matters when the HTTP parser is your bottleneck and you want to move it out of the interpreter. Mangum is not a server in the same sense: it adapts ASGI applications to AWS Lambda and API Gateway, so it is the right answer when there is no long-lived process to run a server in. The ASGI specification is what makes this menu possible, and the README makes the point directly: the protocol decouples the server implementation from the application framework, so the same app can be moved between them.

Maintenance, licence and what an upgrade costs

The repository is not archived, and the last push was on 2026-09-21, the same day as this assessment. Releases have been frequent: 0.53.0 on 2026-09-14, 0.52.4 on 2026-08-19 and 0.52.3 on 2026-08-13. The 0.x version line means minor bumps are where breaking changes can land, so pinning a version and reading CHANGELOG.md before moving is cheaper than tracking the latest tag.

Licensing is straightforward. pyproject.toml declares license = "BSD-3-Clause" with license-files = ["LICENSE.md"], matching the BSD licensed code line in the README. A permissive licence of that kind generally imposes few obligations beyond retaining the notice, but the exact terms are in LICENSE.md and this is not legal advice.

The upgrade cost is mostly in the extras rather than the server code. Because httptools, uvloop, websockets and watchfiles are optional dependencies, a version bump can move the floor on any of them, and a lock file is what keeps that from surprising you. The repository ships a uv.lock, and the dev dependency group pulls uvicorn[standard] so that a sync resolves the extras. If you install with pip, you carry that responsibility yourself.

Editorial conclusion

Adopt Uvicorn if you run an ASGI framework and want a server whose protocol handling you can swap through extras. Skip it if you need Trio, or if you deploy to AWS Lambda, where the README points to Mangum instead. Before committing, decide between pip install uvicorn and pip install 'uvicorn[standard]', and confirm your Python is 3.10 or newer, since pyproject.toml sets requires-python to >=3.10.

Frequently asked questions

What is uvicorn used for?

It is an ASGI web server for Python, used to serve async applications that follow the ASGI specification. The README states that it currently supports HTTP/1.1, HTTP/2 and WebSockets.

What is the difference between FastAPI and uvicorn?

They sit at different layers. FastAPI is a framework that produces an ASGI application, and Uvicorn is the server that runs it. The README's quickstart shows the application contract as an async callable taking scope, receive and send, which is what a framework hands to the server.

What is uvicorn vs Gunicorn?

The README does not compare the two directly. It does say Uvicorn is an ASGI server, while Gunicorn appears in the README's alternative list only indirectly: the ASGI specification decouples the server from the framework, so an application can be moved between servers.

How do you install uvicorn in Python?

The README gives two commands: pip install uvicorn for a minimal, pure Python install, or pip install 'uvicorn[standard]' to add the Cython-based dependencies and optional extras. The project requires Python 3.10 or newer according to pyproject.toml.

How do you use uvicorn with httptools?

You do not enable it with a flag. The README says httptools handles the HTTP protocol if possible when you install the standard extra, so pip install 'uvicorn[standard]' is what brings it in.

How do you pronounce uvicorn?

The project documentation and README do not give a pronunciation, so there is no authoritative answer here. The name is written as Uvicorn throughout the README and the package is installed as uvicorn.

Official sources

  1. Kludex/uvicorn on GitHub
  2. License: BSD-3-Clause
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/kludex-uvicorn.svg)](https://hysenlabs.com/projects/kludex-uvicorn)