FastAPI Integration

Serve any FastAPI application over HTTP/3 with a single line change. nhttp3 is a drop-in replacement for uvicorn that speaks QUIC.

Migration from uvicorn

Before (HTTP/1.1 + HTTP/2)

import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)

After (HTTP/3)

import nhttp3
nhttp3.serve(app, host="0.0.0.0", port=4433,
             certfile="cert.pem", keyfile="key.pem")
Why port 4433?
HTTP/3 uses UDP, not TCP. The standard HTTPS port 443 is typically used by TCP-based servers. 4433 is a common convention for HTTP/3 development. In production, you can use port 443 for both TCP (HTTP/2) and UDP (HTTP/3) simultaneously.

Full Example

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse, StreamingResponse
import nhttp3, asyncio

app = FastAPI(title="My API over HTTP/3")

@app.get("/")
async def root():
    return {"message": "Hello from HTTP/3!"}

@app.post("/echo")
async def echo(request: Request):
    body = await request.body()
    return {"echo": body.decode(), "protocol": "h3"}

@app.get("/stream")
async def stream():
    """HTTP/3 advantage: each SSE chunk is on its own stream."""
    async def generate():
        for i in range(10):
            yield f"data: chunk {i}\n\n"
            await asyncio.sleep(0.1)
    return StreamingResponse(generate(), media_type="text/event-stream")

nhttp3.serve(app, port=4433, certfile="cert.pem", keyfile="key.pem")

Testing Your Server

# GET
curl --http3 https://localhost:4433/ -k

# POST with body
curl --http3 https://localhost:4433/echo -X POST -d "hello" -k

# Streaming response
curl --http3 https://localhost:4433/stream -k --no-buffer

# With timing info
curl --http3 https://localhost:4433/ -k \
  -w "\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nTotal: %{time_total}s\n"

Why HTTP/3 for APIs?

FeatureHTTP/2 (uvicorn)HTTP/3 (nhttp3)
Connection setupTCP + TLS = 2 RTTQUIC + TLS = 1 RTT
Head-of-line blockingYes (shared TCP)None (per-stream)
Network changeConnection dropsConnection migrates
Header compressionHPACKQPACK (50% savings)
MultiplexingOver one TCP connIndependent QUIC streams
When HTTP/3 matters most

Configuration Options

nhttp3.serve(
    app,
    host="0.0.0.0",           # Bind address
    port=4433,                # UDP port
    certfile="cert.pem",      # TLS certificate
    keyfile="key.pem",        # TLS private key
)

Advanced configuration via nhttp3.Config():

config = nhttp3.Config()
config.max_idle_timeout = 60.0          # seconds
config.initial_max_streams_bidi = 200  # concurrent request streams
config.initial_max_data = 50_000_000   # 50MB connection flow control
config.enable_0rtt = True              # 0-RTT resumption

Source Code

examples/fastapi/server.py — Complete example with streaming, echo, and large responses.

Agent-friendly copy

Markdown: docs/guides/python-server.md