Skip to content

HTTP/2

Uvicorn supports HTTP/2, the major revision of the HTTP protocol that provides significant performance improvements over HTTP/1.1.

Experimental Feature

HTTP/2 support is currently experimental and is not enabled by default.

Overview

HTTP/2 introduces several key features:

  • Multiplexing: Multiple requests and responses can be sent simultaneously over a single TCP connection
  • Header compression: HTTP headers are compressed using HPACK, reducing overhead
  • Binary protocol: More efficient parsing compared to HTTP/1.1's text-based format
  • Stream prioritization: Clients can indicate which resources are more important

Enabling HTTP/2

To enable HTTP/2 support in Uvicorn, use the --http2 flag:

uvicorn main:app --http2
import uvicorn

uvicorn.run("main:app", http2=True)

Note

HTTP/2 support requires the h2 package. Install it with:

pip install h2

Connection Methods

HTTP/2 can be established through two different mechanisms: h2 (over TLS) and h2c (cleartext).

When using HTTPS, HTTP/2 is negotiated via ALPN (Application-Layer Protocol Negotiation) during the TLS handshake. This is the most common and recommended way to use HTTP/2.

sequenceDiagram
    participant Client
    participant Server

    Note over Client,Server: TLS Handshake with ALPN

    Client->>Server: ClientHello
    Note right of Client: ALPN: h2, http/1.1

    Server->>Client: ServerHello
    Note right of Server: ALPN: h2

    Note over Client,Server: TLS Handshake Complete

    Client->>Server: HTTP/2 Connection Preface
    Server->>Client: HTTP/2 SETTINGS Frame

    Note over Client,Server: HTTP/2 Connection Established

    Client->>Server: HEADERS (Stream 1)
    Server->>Client: HEADERS + DATA (Stream 1)

For testing it locally, you can generate a self-signed certificate and use it to test the HTTP/2 connection.

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost"

Then create a simple ASGI application to test the connection.

main.py
async def app(scope, receive, send):
    await send({"type": "http.response.start", "status": 200, "headers": []})
    await send({"type": "http.response.body", "body": b"ok"})

Run Uvicorn with the --http2 flag and the SSL certificate files.

uvicorn app:app --http2 --ssl-keyfile key.pem --ssl-certfile cert.pem
import uvicorn

uvicorn.run(
    "app:app",
    http2=True,
    ssl_keyfile="key.pem",
    ssl_certfile="cert.pem",
)

You can test the connection using curl with the --http2 flag.

# Use -k to skip certificate verification for self-signed certs
curl -v --http2 -k https://localhost:8000/

h2c: HTTP/2 Cleartext

HTTP/2 can also be used without TLS through an upgrade mechanism. The client sends an HTTP/1.1 request with upgrade headers, and if the server supports HTTP/2, it responds with 101 Switching Protocols.

sequenceDiagram
    participant Client
    participant Server

    Note over Client,Server: h2c Upgrade Process

    Client->>Server: HTTP/1.1 GET /
    Note right of Client: Headers:<br/>Upgrade: h2c<br/>HTTP2-Settings: [base64]<br/>Connection: Upgrade, HTTP2-Settings

    Server->>Client: HTTP/1.1 101 Switching Protocols
    Note right of Server: Headers:<br/>Upgrade: h2c<br/>Connection: Upgrade

    Note over Client,Server: Connection Upgraded to HTTP/2

    Server->>Client: HTTP/2 SETTINGS Frame
    Client->>Server: HTTP/2 SETTINGS ACK

    Server->>Client: HEADERS + DATA (Stream 1)
    Note right of Server: Response to original request

Using the same main.py from the h2 section above, run Uvicorn with the --http2 flag.

uvicorn main:app --http2
import uvicorn

uvicorn.run("main:app", http2=True)

You can test the connection using curl with the --http2 flag.

curl -v --http2 http://localhost:8000/

Warning

h2c is not supported by web browsers. Browsers only support HTTP/2 over TLS (h2). h2c is primarily useful for internal services, proxies, or testing.

ASGI Scope

When a request comes in over HTTP/2, the ASGI scope will have http_version set to "2":

async def app(scope, receive, send):
    assert scope["type"] == "http"
    print(f"HTTP Version: {scope['http_version']}")  # "2" for HTTP/2
    # ... handle request

Using with Reverse Proxies

In production, Uvicorn is typically deployed behind a reverse proxy like Nginx, Caddy, or HAProxy.

Benefits of using a reverse proxy:

  • TLS termination: The proxy handles SSL/TLS encryption, offloading this work from your application
  • Load balancing: Distribute requests across multiple Uvicorn instances
  • Static file serving: Serve static assets directly without hitting your Python application
  • Request buffering: Buffer slow clients to free up Uvicorn workers
  • Security: Hide your application server details, add rate limiting, and filter malicious requests
  • HTTP/2 to clients: Provide HTTP/2 benefits to clients even if using HTTP/1.1 internally
flowchart LR
    Client <-->|HTTP/2 over TLS| Proxy
    Proxy <-->|HTTP/1.1 or HTTP/2| Uvicorn

    style Client fill:#e1f5fe
    style Proxy fill:#fff3e0
    style Uvicorn fill:#e8f5e9

Proxy HTTP/2 Upstream Support

HTTP/2 Upstream refers to the protocol used between the proxy and the backend server (Uvicorn). While all modern proxies support HTTP/2 for client connections, support for HTTP/2 to backend servers varies.

Multiplexing is HTTP/2's ability to send multiple requests simultaneously over a single TCP connection. Without multiplexing, each request requires its own connection, negating a key benefit of HTTP/2. Some proxies support HTTP/2 upstream but open a new connection per request, which means they don't truly multiplex.

Here's the current state of proxy support (as of 2026-02-02):

Proxy HTTP/2 Upstream Multiplexing Documentation
Envoy Yes Yes Connection Pooling Docs
Caddy Yes Yes reverse_proxy Docs
HAProxy Yes Yes HTTP/2 Docs
Traefik Yes Yes ServersTransport Docs
Apache Partial No mod_proxy_http2 Docs
Nginx Limited No Trac Ticket #923

For most production deployments, using HTTP/1.1 with keepalive connections between the proxy and Uvicorn is recommended. This provides excellent performance while being simple to configure and debug.

h2c Prior Knowledge Not Supported

Uvicorn's h2c implementation uses the HTTP/1.1 upgrade mechanism. It does not support "prior knowledge" h2c where clients send the HTTP/2 connection preface directly. This means proxy configurations using h2c:// URLs will not work.

For HTTP/2 between proxy and Uvicorn, use h2 over TLS (ALPN negotiation).

Performance Considerations

HTTP/2 provides the most benefit when:

  • High latency connections: Multiplexing reduces round-trip overhead
  • Many concurrent requests: Multiple streams share a single connection
  • Large headers: HPACK compression reduces header overhead

For internal, low-latency connections (like proxy to backend), HTTP/1.1 with keepalive often performs comparably to HTTP/2, which is why nginx's approach is still effective.