Every HTTP request your API serves rides on a transport layer most developers never think about. For 25 years, the answer was TCP. Then Google got tired of waiting for TCP to improve, built the QUIC protocol on top of UDP, and the IETF turned it into a standard. HTTP/3 is the version of HTTP built to run on it.
That sounds like plumbing. It mostly is. But this plumbing changes how fast your API connects, how it behaves on flaky mobile networks, and how parallel requests share a connection. If you design or operate APIs, you should know what changed, what didn’t, and how to check what your own endpoints speak today.
One thing stays constant across all of this: your requests, responses, status codes, and JSON payloads look identical on HTTP/1.1, HTTP/2, and HTTP/3. Tools like Apidog test and debug at the API layer, so everything you validate about an endpoint’s behavior holds true no matter which transport version your infrastructure negotiates underneath. If you’ve already read our breakdown of what HTTP/2 is and how to test HTTP/2 APIs, this article picks up where that one ends.
What is the QUIC protocol?
QUIC is a transport protocol standardized in RFC 9000. It runs over UDP instead of TCP, and it rebuilds the features TCP provides (reliability, ordering, congestion control) in user space, per stream, with encryption baked in from the first packet.
Four design decisions define it:
It runs on UDP. TCP is implemented in operating system kernels and middleboxes all over the internet, which makes it nearly impossible to evolve. UDP is a thin envelope with no delivery guarantees, so QUIC builds its own reliability layer on top and can ship improvements as library updates instead of OS upgrades.
TLS 1.3 is built in, not bolted on. With TCP, you complete a TCP handshake, then a separate TLS handshake on top. QUIC merges them. The cryptographic setup happens inside the transport handshake itself, so a new secure connection is ready after a single round trip. There’s no such thing as unencrypted QUIC.
Streams are independent. A QUIC connection carries many streams, and each one is delivered independently. A lost packet only stalls the stream it belongs to. This is the fix for TCP’s head-of-line blocking, which we’ll get to in a moment.
Connections survive network changes. TCP identifies a connection by IP address and port. Change either (walk out of Wi-Fi range, switch to 5G) and the connection dies. QUIC identifies connections by a connection ID instead, so a client can move to a new network and keep the same logical connection alive. No reconnect, no new handshake.
HTTP/3, defined in RFC 9114, is the mapping of HTTP semantics onto QUIC streams. Same methods, same headers, same status codes. Different wire format, different transport.
HTTP/3 vs HTTP/2: what changed in practice
HTTP/2 was a big step over HTTP/1.1. It introduced multiplexing, so many requests could share one TCP connection instead of queuing or opening six parallel sockets. But it kept TCP underneath, and that created a problem HTTP/2 couldn’t solve on its own.
TCP guarantees ordered delivery of a single byte stream. When one packet goes missing, TCP holds back every byte after it until the retransmission arrives, even bytes belonging to completely unrelated HTTP/2 streams. One lost packet freezes all 20 requests multiplexed on the connection. That’s transport-level head-of-line blocking, and on a lossy network it can make HTTP/2 slower than HTTP/1.1 with its multiple connections.
HTTP/3 removes the shared byte stream. Each request maps to its own QUIC stream with its own delivery ordering. Lose a packet carrying stream 5, and streams 6 through 24 keep flowing. Multiplexing finally works the way the HTTP/2 diagrams always claimed.
The handshake math changed too:
| HTTP/2 over TCP+TLS 1.3 | HTTP/3 over QUIC | |
|---|---|---|
| New connection setup | 2 round trips (TCP + TLS) | 1 round trip |
| Resumed connection | 1 round trip | 0 round trips (0-RTT) |
| Lost packet impact | Blocks all streams | Blocks one stream |
| Network switch (Wi-Fi to 5G) | Connection dies, full reconnect | Connection migrates, keeps going |
| Encryption | Optional in theory, separate layer | Mandatory, integrated TLS 1.3 |
The 0-RTT row deserves a caveat. When a client reconnects to a server it has seen before, QUIC lets it send application data in the first packet, before the handshake completes. Great for latency. But 0-RTT data can be captured and replayed by an attacker, so servers must only accept idempotent requests in 0-RTT. A replayed GET is harmless. A replayed POST that charges a credit card is not. If you enable 0-RTT at your edge, make sure non-idempotent API calls are excluded, or confirm your CDN does this for you.
What HTTP/3 means for your APIs
Protocol upgrades only matter if they change something you can measure. Here’s where HTTP/3 moves the needle for API traffic, and where it doesn’t.
Connection setup gets cheaper
A typical mobile client on a 60 ms RTT connection spends around 120 ms on TCP+TLS setup before the first API request even leaves the device. HTTP/3 cuts that to about 60 ms, and near zero on resumption. For an API called from a mobile app that opens fresh connections often (cold starts, background wakeups, short-lived sessions), the saving lands on every one of those first requests. For a server-to-server integration holding a warm connection pool, the handshake is amortized to irrelevance and you’ll notice nothing.
Mobile clients stop dropping connections
Connection migration is the sleeper feature for API teams. A user starts a request on office Wi-Fi, walks to the elevator, and the phone hops to cellular. Over TCP, that in-flight request fails and your client-side retry logic (you have retry logic, right?) kicks in with a full reconnect. Over QUIC, the connection follows the device to the new network. Fewer timeout errors in your client logs, fewer half-completed writes to reason about.
Multiplexing without the failure mode
For REST APIs, the HOL blocking fix matters most when a client fires many requests in parallel: a dashboard hydrating 15 widgets, a sync engine pushing a batch of updates. On a clean network, HTTP/2 and HTTP/3 perform about the same. Add 1-2% packet loss (crowded conference Wi-Fi, subway cellular), and HTTP/3 keeps parallel requests independent while HTTP/2 stalls them in lockstep.
gRPC mostly stays on HTTP/2 for now
gRPC is bound to HTTP/2 by design; its wire contract depends on HTTP/2 framing and trailers. The gRPC ecosystem hasn’t standardized an HTTP/3 mapping, and the mainstream implementations (Go, Java, Python, Node) don’t ship it. .NET’s Kestrel server can serve gRPC over HTTP/3 as an experimental capability, but treat that as the exception. If your architecture leans on gRPC and HTTP/2 for internal API performance, an HTTP/3 migration isn’t something you need to plan this year.
Streaming and real-time traffic
Server-Sent Events work over HTTP/3 unchanged, since SSE is an ordinary long-lived HTTP response. WebSockets are trickier: the WebSocket upgrade was designed for TCP, and its HTTP/3 equivalent (RFC 9220, plus the emerging WebTransport API) has patchy support. If you’re weighing WebSockets against plain HTTP for a real-time feature, HTTP/3 availability shouldn’t drive the decision yet.
The honest part: when HTTP/3 won’t help
Most API latency problems have nothing to do with the transport protocol. If your endpoint takes 400 ms because of an unindexed database query, HTTP/3 will deliver that slow response 60 ms sooner. Caching, payload design, N+1 queries, and connection reuse dominate real-world API performance, and you should exhaust those before thinking about transport. A structured API performance testing pass will usually surface wins 10x larger than a protocol upgrade.
HTTP/3 shines in specific conditions:
- High-latency links, where saving round trips is a fixed percentage win
- Lossy networks, where HOL blocking elimination compounds
- Mobile clients switching networks mid-session
- Many short connections rather than few long ones
For a typical JSON API consumed by servers in the same region over reliable networks, the difference is measurable in benchmarks and invisible to users. Two other practical notes: UDP port 443 is blocked in some corporate networks (clients fall back to HTTP/2 automatically, so nothing breaks), and QUIC’s user-space crypto currently costs more server CPU per connection than tuned kernel TCP.
Current support: who speaks HTTP/3 today
Adoption is further along than most backend developers assume:
- Browsers: Chrome, Edge, Firefox, and Safari all ship HTTP/3 enabled by default.
- CDNs and edges: Cloudflare, Fastly, Akamai, and CloudFront support it; on Cloudflare it’s a toggle. For most teams, this is the practical path: terminate HTTP/3 at the edge, keep HTTP/1.1 or HTTP/2 from edge to origin.
- Servers: Nginx added experimental HTTP/3 in 1.25 with
listen 443 quic;. Caddy enables it by default. LiteSpeed and HAProxy support it. Apache httpd doesn’t. - Runtimes: Node.js has no stable built-in HTTP/3 server support, which is another reason edge termination is the common deployment.
- curl: supports it with the
--http3flag when built against an HTTP/3-capable TLS stack; see the curl HTTP/3 docs for which builds include it.
How to check if your API serves HTTP/3
Discovery works through the Alt-Svc response header. A server advertising HTTP/3 answers your first (HTTP/2) request with something like:
alt-svc: h3=":443"; ma=86400
That tells the client: this same service is available over HTTP/3 on UDP port 443 for the next 24 hours. Check for it with curl:
curl -sI https://www.cloudflare.com | grep -i alt-svc
# alt-svc: h3=":443"; ma=86400
To make the request over HTTP/3 directly (requires an HTTP/3-enabled curl build):
curl --http3 -I https://cloudflare-quic.com
# HTTP/3 200
The status line reports HTTP/3 instead of HTTP/2. In Chrome DevTools, open the Network tab, right-click the column header, enable the Protocol column, and look for h3 next to your API calls. In production, add the negotiated protocol to your access logs; the split between h2 and h3 traffic tells you how many of your clients get the benefit.
While you’re verifying transport, verify behavior too. Point Apidog at the same endpoints and assert on status codes, response schemas, and latency budgets. Transport-level wins are worthless if the API contract underneath is broken, and contract checks are exactly the layer where a protocol change can’t save you. Download Apidog free and run the same test suite before and after you flip HTTP/3 on at your edge; the diff in response times on mobile networks is your real-world answer, not the benchmark headlines.
FAQ
Is HTTP/3 faster than HTTP/2?
On clean, low-latency networks: barely. On lossy or high-latency networks: yes, often noticeably, because HTTP/3 saves a handshake round trip and a single lost packet no longer stalls every multiplexed request. Measure with your own traffic profile before claiming the win. And remember HTTP/2 remains excellent; if you hit connection errors there, they’re usually TLS-layer issues like the SSLV3_ALERT_HANDSHAKE_FAILURE problem rather than protocol limits.
Does HTTP/3 use TCP?
No. HTTP/3 runs on QUIC, which runs on UDP, typically port 443. QUIC reimplements the reliability, ordering, and congestion control TCP used to provide, but per stream and in user space. If UDP 443 is blocked on a network, clients fall back to HTTP/2 over TCP automatically.
Do I need to change my API code for HTTP/3?
Almost never. HTTP semantics are unchanged: same methods, headers, status codes, and bodies. The work lives in infrastructure (enabling it at your CDN, load balancer, or server) plus one design check: make sure 0-RTT early data is restricted to idempotent requests.
Can I use gRPC over HTTP/3?
Mostly no, for now. gRPC’s wire format is tied to HTTP/2, and mainstream gRPC libraries don’t ship HTTP/3 transports. .NET has experimental support. Keep gRPC services on HTTP/2 and adopt HTTP/3 where it pays off first: public, browser-facing, and mobile-facing REST endpoints.



