Key Differences Between HTTP/1.1, HTTP/2, and HTTP/3: Complete Protocol Comparison

HTTP/1.1 relies on text-based messaging over TCP with sequential request processing, HTTP/2 introduces binary framing and multiplexing over TCP, and HTTP/3 replaces TCP entirely with QUIC over UDP to eliminate head-of-line blocking and reduce connection latency.

The HyperText Transfer Protocol has evolved through three major architectural revisions to address the performance bottlenecks of modern web applications. Understanding the differences between HTTP/1.1, HTTP/2, and HTTP/3 is critical for optimizing network stack implementations, as detailed in the CyC2018/CS-Notes repository's networking documentation.

Transport Layer and Connection Architecture

The fundamental distinction between these protocols lies in their transport layer dependencies.

HTTP/1.1 operates exclusively over TCP, establishing persistent connections that allow multiple requests over a single connection, but still requiring new TCP handshakes for each distinct host. According to notes/HTTP.md in the CS-Notes repository, this version relies on the standard three-way TCP handshake for every connection initialization.

HTTP/2 maintains TCP as the underlying transport but implements a single TCP connection with multiple concurrent streams. This reduces handshake overhead while maintaining reliable, ordered delivery through TCP's congestion control mechanisms.

HTTP/3 abandons TCP entirely in favor of QUIC, which runs over UDP. As implemented in the protocol specifications referenced in notes/HTTP.md, QUIC incorporates TLS 1.3 directly into its handshake mechanism, reducing round trips and enabling connection migration across network changes without interruption.

Message Framing and Head-of-Line Blocking

Each protocol handles message serialization differently, directly impacting latency characteristics.

HTTP/1.1 uses text-based framing consisting of a start line, headers, a blank line, and an optional body. This human-readable format introduces parsing overhead and suffers from head-of-line blocking at the application layer—if one request stalls, all subsequent requests on the same TCP connection must wait.

HTTP/2 transitions to binary framing with distinct frame types including HEADERS, DATA, and SETTINGS frames. While this eliminates application-layer head-of-line blocking through multiplexing, TCP-level blocking persists because packet loss in the underlying TCP stream stalls all multiplexed streams.

HTTP/3 implements binary frames over QUIC streams, which are independent and unordered. Because QUIC handles packet loss at the stream level rather than connection level, a lost packet affects only the specific stream, not all concurrent streams, as illustrated in notes/pics/86e6a91d-a285-447a-9345-c5484b8d0c47.png.

Header Compression Mechanisms

Modern web applications generate numerous small requests, making header compression critical for bandwidth efficiency.

HTTP/1.1 transmits headers as plain text with every request, creating significant overhead when sending repetitive metadata like cookies and user agent strings.

HTTP/2 introduces HPACK compression, utilizing static and dynamic tables to eliminate duplication. The CS-Notes repository references this in notes/pics/_u4E0B_u8F7D.png, which illustrates how HPACK maintains stateful compression contexts between endpoints.

HTTP/3 employs QPACK, an adaptation of HPACK designed for QUIC's out-of-order delivery model. QPACK avoids head-of-line blocking in the compression layer that could occur when HPACK updates are delayed due to packet loss.

Server Push and Prioritization

Advanced features vary significantly across versions.

HTTP/1.1 provides no native server push capability; clients must explicitly request every resource.

HTTP/2 implements server push through PUSH_PROMISE frames, allowing servers to preemptively send resources before the client requests them. The mechanism is visualized in notes/pics/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png from the CS-Notes repository.

HTTP/3 maintains equivalent push functionality but leverages QUIC's stream prioritization, which implements dependency and weight signaling with improved loss-recovery semantics compared to HTTP/2's prioritization scheme.

Detecting Protocol Versions in Practice

You can verify which protocol version your client is using through standard command-line tools and browser developer tools.

Curl Protocol Verification

Use the --http1.1, --http2, and --http3 flags to force specific versions and observe the negotiated protocol in verbose output:


# Force HTTP/1.1

curl -v --http1.1 https://example.com

# Force HTTP/2 (requires nghttp2 support)

curl -v --http2 https://example.com

# Force HTTP/3 (requires quiche or lsquic support)

curl -v --http3 https://example.com

The -v flag reveals the negotiated protocol in the response headers.

Node.js Implementation Examples

Different modules handle each protocol version:

// HTTP/1.1 (standard module)
const http = require('http');
http.get('http://example.com', res => {
  console.log('HTTP/1.1 status:', res.statusCode);
});

// HTTP/2 (built-in http2 module)
const http2 = require('http2');
const client = http2.connect('https://example.com');
const req = client.request({ ':path': '/' });
req.on('response', (headers) => {
  console.log('HTTP/2 status:', headers[':status']);
});
req.end();

// HTTP/3 (experimental, Node.js >= v22)
const { createQuicSocket } = require('net');
(async () => {
  const socket = createQuicSocket({ 
    endpoint: { address: 'example.com', port: 443 } 
  });
  const stream = await socket.openStream();
  stream.write('GET / HTTP/3\r\n\r\n');
  stream.on('data', (data) => console.log(data.toString()));
})();

Browser Developer Tools

In Chrome DevTools, open the Network panel and examine the Protocol column. Entries display h2 for HTTP/2 and h3 for HTTP/3, while HTTP/1.1 appears as http/1.1.

Summary

  • Transport: HTTP/1.1 and HTTP/2 use TCP; HTTP/3 uses QUIC over UDP with integrated TLS 1.3
  • Framing: HTTP/1.1 uses text; HTTP/2 and HTTP/3 use binary frames
  • Multiplexing: HTTP/1.1 allows one request per connection; HTTP/2 multiplexes over TCP; HTTP/3 eliminates TCP head-of-line blocking entirely
  • Compression: HTTP/1.1 has none; HTTP/2 uses HPACK; HTTP/3 uses QPACK optimized for QUIC streams
  • Connection Setup: HTTP/3 reduces latency through combined handshake and supports connection migration across networks

Frequently Asked Questions

What is the main advantage of HTTP/3 over HTTP/2?

HTTP/3 eliminates TCP head-of-line blocking by using QUIC over UDP. While HTTP/2 multiplexes streams over a single TCP connection, any packet loss in TCP stalls all streams. QUIC handles packet loss at the individual stream level, allowing other streams to continue uninterrupted.

Why does HTTP/2 still suffer from head-of-line blocking if it supports multiplexing?

HTTP/2 multiplexes multiple streams over a single TCP connection. Because TCP guarantees ordered delivery of bytes, if a packet is lost, TCP pauses the entire connection until retransmission succeeds. This stalls all HTTP/2 streams, even those whose data arrived successfully. The notes/HTTP.md file in CS-Notes explains this architectural limitation.

Is HTTP/3 backward compatible with HTTP/1.1 and HTTP/2?

HTTP/3 is not directly backward compatible at the transport layer because it requires QUIC/UDP support rather than TCP. However, through Application-Layer Protocol Negotiation (ALPN), clients and servers can fall back to HTTP/2 or HTTP/1.1 if QUIC connectivity fails, ensuring interoperability.

When should developers choose HPACK versus QPACK?

You use HPACK with HTTP/2 over TCP connections, where the ordered stream guarantees that encoder and decoder contexts remain synchronized. You use QPACK with HTTP/3 over QUIC, where independent streams require special handling to prevent head-of-line blocking in the compression layer due to out-of-order packet delivery.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →