HTTP/1.1 vs HTTP/2 vs HTTP/3
HTTP/1.1, HTTP/2, and HTTP/3 expose largely the same application-level request and response model, but they move those requests across the network very differently. The differences become important when applications make many concurrent requests, operate over high-latency networks, or experience packet loss.
HTTP/1.1 commonly relies on multiple TCP connections for concurrency. HTTP/2 multiplexes many streams over one TCP connection. HTTP/3 keeps multiplexing but replaces TCP with QUIC over UDP, allowing independent streams to recover from packet loss without TCP-level head-of-line blocking across the entire connection.
For backend engineers, protocol selection is primarily about connection behavior, multiplexing, latency, failure isolation, infrastructure compatibility, and operational complexity rather than differences in REST APIs or HTTP methods.
Table of Contents
- HTTP as a Request-Response Protocol
- HTTP/1.1
- HTTP/2
- HTTP/3
- Comparing HTTP Versions
- Production Design Example
- Common Mistakes
- Production Checklist
- Conclusion
- More Articles to Read
HTTP as a Request-Response Protocol
At the application level, HTTP versions share familiar concepts: methods, URLs, headers, status codes, request bodies, and response bodies.
An application can expose the same endpoint regardless of whether the client communicates using HTTP/1.1, HTTP/2, or HTTP/3.
What Remains the Same
A logical request still looks like:
GET /api/shipments/123
Host: api.example.com
Authorization: Bearer ...
Accept: application/json
And the application can still produce:
{
"id": 123,
"status": "in_transit",
"carrier": "carrier-a"
}
Controllers, routing, authentication, caching semantics, and most application code generally do not need separate implementations for each HTTP version.
The major differences exist below these application semantics.
What Changes Between Versions
The versions differ substantially in how requests are represented and transported.
| Characteristic | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| Primary transport | TCP | TCP | QUIC over UDP |
| Message representation | Text-oriented framing | Binary framing | Binary framing over QUIC |
| Multiplexing | Limited per connection | Multiple streams | Multiple independent streams |
| Header compression | No protocol-level equivalent | HPACK | QPACK |
| Transport-level head-of-line blocking across streams | TCP connection affected | Yes | Avoided between independent QUIC streams |
The biggest architectural progression is therefore:
HTTP/1.1
Multiple connections for concurrency
|
v
HTTP/2
Multiple streams over one TCP connection
|
v
HTTP/3
Multiple streams over QUIC
with independent stream recovery
HTTP/1.1
HTTP/1.1 remains simple, mature, and broadly supported. Its major limitation for modern workloads is how concurrency interacts with TCP connections.
A single connection processes an ordered sequence of bytes, making concurrent independent request handling less flexible than newer protocols.
Persistent Connections
Reusing TCP connections avoids repeatedly paying connection-establishment costs.
Without connection reuse:
TCP connect
TLS handshake
Request
Response
Close
TCP connect
TLS handshake
Request
Response
Close
With persistent connection:
TCP connect
TLS handshake
Request 1
Response 1
Request 2
Response 2
Request 3
Response 3
Persistent connections are therefore critical for efficient HTTP/1.1 communication.
Backend HTTP clients should normally use connection pools rather than constructing a completely new transport connection for every request.
import httpx
with httpx.Client() as client:
shipment = client.get(
"https://api.example.com/shipments/123"
)
events = client.get(
"https://api.example.com/shipments/123/events"
)
The client can reuse existing connections rather than repeatedly creating them.
Concurrency Limitations
Suppose a client needs four independent resources.
Conceptually, serial use of one connection looks like:
Connection
Request A ---> Response A
Request B ---> Response B
Request C ---> Response C
Request D ---> Response D
HTTP/1.1 pipelining exists but has historically seen limited practical use, and modern clients commonly achieve concurrency by opening multiple connections.
Connection 1 ---> Request A
Connection 2 ---> Request B
Connection 3 ---> Request C
Connection 4 ---> Request D
This works, but additional connections consume resources across clients, servers, load balancers, proxies, NAT infrastructure, and firewalls.
Advantages:
- simple and mature
- extremely broad compatibility
- easy to inspect and troubleshoot
- works well for many ordinary backend workloads
Disadvantages:
- concurrency often requires multiple connections
- more connection-management overhead
- repeated headers can add unnecessary bytes
- less efficient for many concurrent requests
When to Use: HTTP/1.1 remains reasonable when compatibility matters most, request concurrency is limited, or infrastructure does not support newer versions end to end.
HTTP/2
HTTP/2 changes the wire representation of HTTP while preserving application semantics. Requests and responses are divided into binary frames associated with logical streams.
The central improvement is multiplexing.
Streams and Multiplexing
Instead of requiring separate TCP connections for independent concurrent requests, HTTP/2 can interleave frames belonging to multiple streams on one connection.
Single TCP Connection
+--------------------------------------+
| Stream 1 frame |
| Stream 3 frame |
| Stream 1 frame |
| Stream 5 frame |
| Stream 3 frame |
| Stream 5 frame |
+--------------------------------------+
Conceptually:
Client
|
|==== one TCP connection =================|
| |
+---- Stream 1 ---- GET /shipment --------+
+---- Stream 3 ---- GET /customer --------+
+---- Stream 5 ---- GET /tracking --------+
+---- Stream 7 ---- GET /pricing ---------+
|
Server
One slow HTTP request does not inherently require the application to wait before sending another request on a different stream.
HTTP/2 also compresses HTTP headers using HPACK, which can reduce repeated metadata when many requests share similar headers.
This is useful for APIs where headers such as authorization, content negotiation, cookies, tracing information, and user-agent metadata are repeatedly transmitted.
TCP Head-of-Line Blocking
HTTP/2 solves application-layer request serialization, but all streams still share one ordered TCP byte stream.
Suppose packets carrying data from several HTTP/2 streams are transmitted:
TCP packets
[ A1 ][ B1 ][ C1 ][ A2 ][ B2 ][ C2 ]
X
packet lost
TCP must recover missing bytes before later bytes can be delivered in order to the HTTP/2 layer.
As a result, packet loss affecting one portion of the TCP stream can temporarily delay data belonging to otherwise independent HTTP/2 streams.
HTTP/2 streams
|
+-- Stream A
+-- Stream B
+-- Stream C
|
v
Single ordered TCP stream
|
X packet loss
|
v
Later TCP data waits for recovery
This is transport-level head-of-line blocking.
HTTP/2 therefore removes an important HTTP/1.1 concurrency limitation but cannot remove TCP's ordered-delivery behavior.
Advantages:
- multiplexes many requests over fewer connections
- reduces connection proliferation
- compresses headers
- works well for high-concurrency APIs
- broad support across modern infrastructure
Disadvantages:
- all streams still share TCP transport behavior
- packet loss can temporarily affect multiple streams
- binary framing makes raw debugging less human-readable
- proxies and load balancers must correctly support HTTP/2 behavior
When to Use: HTTP/2 is a strong default for modern APIs and service communication when infrastructure supports it and many concurrent requests benefit from multiplexing.
HTTP/3
HTTP/3 changes the transport foundation. Instead of running HTTP over TCP, it runs over QUIC, which itself runs over UDP.
QUIC provides features traditionally associated with transport protocols, including reliable delivery, congestion control, connection management, encryption, and stream multiplexing.
QUIC Transport
The simplified protocol stacks look like:
HTTP/1.1 HTTP/2 HTTP/3
HTTP HTTP/2 HTTP/3
| | |
TLS TLS QUIC
| | |
TCP TCP UDP
| | |
IP IP IP
HTTP/3 does not simply send unreliable HTTP requests over UDP. QUIC implements reliable transport semantics above UDP while using a design better suited to multiplexed streams.
QUIC also integrates TLS 1.3 into the transport handshake rather than treating transport establishment and TLS establishment as entirely separate protocol phases.
This can reduce setup latency, particularly when network round-trip time is significant.
Independent Stream Recovery
The major architectural improvement is that loss in one QUIC stream does not require unrelated streams to wait for the missing data.
QUIC Connection
Stream A: [ A1 ][ A2 ][ A3 ]
Stream B: [ B1 ][ X ][ B3 ]
Stream C: [ C1 ][ C2 ][ C3 ]
|
v
Stream B waits for B2 recovery
Streams A and C can continue
Reliable ordering still exists inside each stream, but it is not imposed globally across all HTTP streams by one TCP byte stream.
This can improve behavior on networks with packet loss, variable connectivity, or higher latency.
QUIC also supports connection migration. A connection is not identified solely by the traditional IP-address and port tuple in the same way as TCP.
This can help when a client changes network paths, such as moving from Wi-Fi to a mobile network.
Advantages:
- independent transport streams
- avoids TCP head-of-line blocking between HTTP streams
- integrated modern encryption
- efficient connection establishment
- better behavior for changing client network paths
Disadvantages:
- more complex protocol implementation
- UDP handling can differ across existing network infrastructure
- observability and troubleshooting tools may require adaptation
- backend infrastructure may terminate HTTP/3 before forwarding traffic using another HTTP version
When to Use: HTTP/3 is particularly valuable for internet-facing applications serving geographically distributed or mobile clients where latency, packet loss, and network changes matter.
Comparing HTTP Versions
The evolution from HTTP/1.1 to HTTP/3 is largely an attempt to improve concurrency and reduce the cost of network latency without changing the basic HTTP programming model.
Latency and Connection Behavior
Consider a client requesting several independent resources.
HTTP/1.1
TCP 1 ---> Request A
TCP 2 ---> Request B
TCP 3 ---> Request C
TCP 4 ---> Request D
HTTP/2
TCP connection
|
+-- Stream A
+-- Stream B
+-- Stream C
+-- Stream D
HTTP/3
QUIC connection
|
+-- Independent Stream A
+-- Independent Stream B
+-- Independent Stream C
+-- Independent Stream D
HTTP/2 significantly reduces the need for many parallel TCP connections. HTTP/3 retains that advantage while improving stream isolation during transport-level packet loss.
However, protocol version alone does not determine request latency.
Real performance depends on:
- network round-trip time
- packet-loss rate
- connection reuse
- request concurrency
- payload size
- server processing time
- load-balancer behavior
- TLS configuration
- client implementation
- connection-pool configuration
An HTTP/1.1 connection reused inside a low-latency private network can outperform a poorly configured HTTP/3 path. Architecture matters more than version numbers alone.
Backend and Infrastructure Trade-Offs
HTTP version selection is also not necessarily end-to-end.
A production request can use different protocol versions on different network segments:
Browser
|
| HTTP/3
v
CDN
|
| HTTP/2
v
Load Balancer
|
| HTTP/1.1
v
Application
This is common because edge infrastructure terminates client connections and establishes separate connections toward backend origins.
Consequently, enabling HTTP/3 at the edge does not automatically mean application servers receive HTTP/3 traffic.
| Use Case | Typical Choice | Reason |
|---|---|---|
| Legacy integration | HTTP/1.1 | Maximum compatibility |
| Modern internal API | HTTP/2 | Multiplexing with mature infrastructure support |
| High-concurrency RPC | HTTP/2 | Efficient multiple streams |
| Public web edge | HTTP/2 and HTTP/3 | Broad compatibility plus modern transport |
| Mobile internet traffic | HTTP/3 when supported | Better behavior under loss and network migration |
The transport differences between TCP and UDP are covered in TCP vs UDP: Choosing the Right Protocol.
Production Design Example
Consider a global logistics platform serving browser clients, mobile applications, partner APIs, and internal backend services.
The system does not require one HTTP version everywhere. Each network segment can use the protocol that best fits its requirements and infrastructure.
Architecture
Browsers / Mobile Apps
|
| HTTP/2 or HTTP/3
v
Global CDN / Edge
|
| HTTP/2
v
Regional Load Balancer
|
+-------------------+
| |
v v
Shipment API Tracking API
| |
| HTTP/2 | HTTP/2
v v
Pricing Service Carrier Service
|
| TCP
v
PostgreSQL
The edge supports HTTP/3 for compatible clients while retaining HTTP/2 or HTTP/1.1 compatibility for clients that cannot use it.
The CDN terminates the client connection. Traffic between the CDN and regional load balancer can use HTTP/2 independently of the client-side protocol.
Internal service communication also uses HTTP/2 where multiplexing provides value.
Request and Failure Flow
Suppose a mobile application opens a shipment tracking screen and concurrently requests:
GET /shipments/123
GET /shipments/123/events
GET /shipments/123/documents
GET /shipments/123/carrier
GET /shipments/123/eta
With HTTP/1.1, efficient concurrency commonly requires multiple connections or careful reuse of a connection pool.
With HTTP/2, these requests can become independent streams over one TCP connection:
TCP Connection
Stream 1 ---> shipment
Stream 3 ---> events
Stream 5 ---> documents
Stream 7 ---> carrier
Stream 9 ---> ETA
Now suppose packet loss occurs on the mobile network.
HTTP/2
|
v
TCP packet lost
|
v
TCP waits for missing bytes
|
v
Multiple HTTP streams can be delayed
With HTTP/3:
HTTP/3
|
v
QUIC packet carrying Stream 5 data lost
|
+---- Stream 5 waits for recovery
|
+---- Stream 1 continues
+---- Stream 3 continues
+---- Stream 7 continues
+---- Stream 9 continues
This does not make HTTP/3 immune to congestion or packet loss. Lost data still needs recovery when reliable delivery is required. The improvement is that loss associated with one stream does not impose TCP's connection-wide ordered-delivery blocking on unrelated streams.
Production monitoring should distinguish client-facing and origin-facing protocol behavior.
Useful metrics include:
- requests by HTTP version
- connection establishment latency
- connection reuse rate
- active connections
- requests per connection
- concurrent streams
- TLS handshake latency
- request latency by protocol version
- connection resets
- TCP retransmissions
- QUIC connection failures
- HTTP/3 fallback rate
- edge-to-origin latency
Comparing HTTP versions without separating network conditions can produce misleading conclusions. Mobile users experiencing packet loss and internal services operating inside one data center have fundamentally different network environments.
Common Mistakes
HTTP upgrades can improve network efficiency, but protocol versions do not fix inefficient application architecture. Excessive requests, poor connection reuse, slow dependencies, and incorrect timeout policies remain problems regardless of the HTTP version.
| Mistake | Production Impact | Better Approach |
|---|---|---|
| Opening a new HTTP/1.1 connection per request | Repeated connection and TLS setup increases latency. | Use persistent connections and pooling. |
| Assuming HTTP/2 uses one request at a time | Multiplexing benefits are overlooked. | Understand HTTP/2 streams and concurrency. |
| Assuming HTTP/2 eliminates all head-of-line blocking | TCP packet loss can still delay multiple streams. | Distinguish HTTP-layer multiplexing from TCP ordering. |
| Assuming HTTP/3 is unreliable because it uses UDP | QUIC's reliability model is misunderstood. | Treat QUIC as a reliable transport implemented over UDP. |
| Assuming HTTP/3 is always faster | Complexity is added without measurable benefit. | Benchmark under representative network conditions. |
| Assuming one HTTP version exists end to end | Debugging targets the wrong network segment. | Observe protocols separately at each hop. |
| Ignoring connection reuse | Handshake costs dominate short requests. | Monitor and tune persistent connections. |
| Using excessive parallel HTTP/1.1 connections | Connection capacity is wasted across infrastructure. | Bound pools or use multiplexed protocols. |
| Upgrading protocol without measuring performance | No evidence exists that the change improves production behavior. | Measure latency, loss, connections, and resource usage. |
| Expecting HTTP upgrades to fix slow application code | Database and service bottlenecks remain unchanged. | Profile the complete request path. |
Production Checklist
HTTP protocol decisions should be made from observed traffic patterns and network conditions rather than version numbers alone.
- Enable persistent connections. Avoid unnecessary transport and TLS handshakes.
- Reuse HTTP clients. Maintain connection pools instead of constructing clients per request.
- Measure request concurrency. Determine whether multiplexing provides meaningful value.
- Prefer HTTP/2 for concurrent modern APIs. Use multiplexing when infrastructure supports it reliably.
- Evaluate HTTP/3 at internet-facing edges. Test workloads exposed to latency, packet loss, and changing networks.
- Retain protocol fallback. Do not assume every client or network path supports HTTP/3.
- Inspect every network segment. Client-to-edge and edge-to-origin connections may use different protocols.
- Monitor connection reuse. Poor reuse can eliminate expected protocol benefits.
- Monitor connections and streams. Understand concurrency at both transport and application layers.
- Measure handshake latency. Connection setup becomes important for short-lived traffic.
- Track protocol distribution. Know what percentage of production traffic actually uses each HTTP version.
- Track fallback behavior. HTTP/3 failures may silently fall back to another protocol.
- Test packet loss. Compare protocol behavior under realistic degraded networks.
- Test high round-trip latency. Geographic distance changes handshake and request costs.
- Configure explicit timeouts. Protocol improvements do not replace bounded waiting.
- Protect backend capacity. Multiplexing can increase request concurrency toward downstream services.
- Benchmark complete request paths. Include proxies, TLS, load balancers, and application processing.
- Separate transport from application performance. Diagnose database and service latency independently of HTTP behavior.
Conclusion
HTTP/1.1, HTTP/2, and HTTP/3 preserve the same fundamental HTTP request-response model while progressively changing how concurrent communication is transported.
HTTP/1.1 relies heavily on connection reuse and often multiple connections for concurrency. HTTP/2 introduces multiplexed streams over TCP. HTTP/3 moves those streams to QUIC, allowing transport recovery to occur independently across streams and improving behavior on lossy or changing networks.
Key Takeaway: HTTP/2 is a strong choice for efficient multiplexed communication across modern infrastructure, while HTTP/3 provides additional benefits for latency-sensitive and unreliable network paths. The best protocol is the one that improves measured production behavior without introducing unnecessary operational complexity.
Comments (0)