TCP and UDP are the two transport-layer workhorses that underpin almost every networked application. The choice between them is rarely made directly by application developers — it is made implicitly when you choose a protocol like HTTP (TCP) or DNS (UDP). Understanding the trade-offs matters when you are designing a real-time system, debugging latency, or evaluating whether QUIC solves your head-of-line-blocking problem.
What changed in 2026
- HTTP/3 (QUIC) is widely deployed — Cloudflare, Google, and Fastly serve the majority of their traffic over HTTP/3. Most browsers enable it by default. QUIC runs over UDP but implements its own reliability and ordering, making the TCP vs UDP decision more nuanced.
- WebTransport is production-ready — the browser API for multiplexed, low-latency bidirectional streams over HTTP/3 (QUIC) is a practical alternative to WebSocket for real-time web apps.
- QUIC is in the Linux kernel — kernel-level QUIC support landed in Linux 6.9, reducing the overhead of user-space QUIC implementations.
- WebRTC DataChannel is the standard for P2P — peer-to-peer data in browsers uses SCTP over DTLS over UDP. TCP is not used for P2P.
The core difference
TCP (Transmission Control Protocol):
- Three-way handshake before any data flows
- Every byte is acknowledged; lost packets are retransmitted
- Bytes arrive in order — if packet 5 is lost, packets 6–10 wait
- Head-of-line blocking: one lost packet stalls the whole stream
UDP (User Datagram Protocol):
- No handshake — send and forget
- No acknowledgements, no retransmissions
- Packets can arrive out of order, duplicated, or not at all
- No head-of-line blocking — each datagram is independent
TCP flow for a 4-packet message:
Client → [SYN] → Server
Client ← [SYN-ACK] ← Server
Client → [ACK] → Server
Client → [data 1] → Server → [ACK]
Client → [data 2] lost
Client ← [dup ACK] ← Server (retry)
Client → [data 2] → Server → [ACK]
Client → [data 3] → Server → [ACK]
UDP: Client → [data 1] [data 2] [data 3] [data 4] → Server (no ACK, no order guarantee)
Protocol selection table
| Use case |
Protocol |
Why |
| HTTP/1.1, HTTP/2 REST APIs |
TCP |
Reliability required |
| HTTP/3 (modern web) |
UDP (via QUIC) |
Reduced HoL blocking |
| Database connections (Postgres, MySQL) |
TCP |
Transactions need ordered reliability |
| DNS queries |
UDP |
One-shot, fast; fallback to TCP for large responses |
| Live video streaming (RTP/RTSP) |
UDP |
Dropped frame < stalled stream |
| Online gaming (real-time state) |
UDP |
Stale state is useless; speed beats completeness |
| File transfer (FTP, SFTP, rsync) |
TCP |
Every byte must arrive |
| Telemetry / metrics (StatsD) |
UDP |
Volume too high for ACK overhead |
| WebSocket |
TCP |
Built on HTTP upgrade |
| WebTransport |
UDP (QUIC) |
Multiplexed, low-latency browser streams |
| VoIP (SIP/RTP) |
UDP |
Latency more important than packet loss |
QUIC: the practical middle ground
QUIC is what most teams should reach for when they need low-latency + reliability:
TCP: one stream, head-of-line blocking on loss
HTTP/2 over TCP: multiple logical streams, but HoL blocking at TCP layer
QUIC: multiple independent streams over UDP; loss in stream A does not block stream B
# Python example: making an HTTP/3 request with httpx + h3
import httpx
async with httpx.AsyncClient(http2=True, http3=True) as client:
response = await client.get("https://example.com/api/data")
print(response.http_version) # HTTP/3 if server supports it
How to pick
- Web API or browser application? → Use HTTP/2 or HTTP/3. The protocol is handled by your stack; you do not implement TCP directly.
- Real-time game or simulation? → UDP with application-layer sequencing. Each game tick is independent; retransmitting stale state wastes bandwidth.
- Live video or audio (low latency)? → UDP (RTP). A dropped frame is better than a delayed one.
- High-volume telemetry (metrics, logs)? → UDP (StatsD, syslog UDP). The volume makes TCP ACK overhead measurable.
- Peer-to-peer browser communication? → WebRTC DataChannel (SCTP over UDP) or WebTransport.
Common mistakes
Building a custom reliability layer on UDP for a general-purpose API. Retransmit logic, congestion control, and flow control are solved problems — use QUIC or just TCP. Custom UDP reliability is invariably incomplete.
Assuming UDP is always faster. The speed advantage only matters when (a) latency is critical, (b) you can tolerate loss, and (c) volume is high enough that ACK overhead is measurable. For low-frequency API calls, the difference is microseconds.
Not accounting for UDP being blocked by firewalls. Many enterprise and mobile networks block non-DNS UDP. QUIC/HTTP/3 stacks fall back to TCP; custom UDP protocols may not.
Using TCP for real-time game state and blaming the network. Head-of-line blocking at 1% packet loss makes a TCP game feel laggy even on a good connection. Switch to UDP with sequence numbers and dead-reckoning.
What to skip
- Raw socket programming for application-layer protocols — use a library (libwebsockets, ngtcp2 for QUIC, Netty for JVM, tokio::net for Rust).
- UDP for database connections — every database client library uses TCP. There is no reason to change this.
- SCTP as a TCP alternative in new designs — QUIC solves the same multi-stream problem with wider implementation support.
FAQ
Does QUIC replace TCP?
For new protocols designed for the web: yes, gradually. QUIC (HTTP/3) is the direction for HTTP traffic. TCP will remain dominant for databases, SSH, email, and existing infrastructure for many years.
Why does DNS use UDP?
DNS queries are a single question and answer that fit in one packet. UDP avoids the 3-way handshake overhead. DNS falls back to TCP for responses larger than 512 bytes (zone transfers, DNSSEC records).
Can I use QUIC outside the browser?
Yes. Libraries like ngtcp2 (C), quic-go (Go), and Quinn (Rust) implement QUIC for server-to-server communication. gRPC has experimental QUIC transport support.
What is the performance difference in practice?
For a single request, the difference is typically under 5 ms. For multiplexed connections with packet loss, QUIC reduces latency by 20–40% vs HTTP/2 over TCP due to eliminated head-of-line blocking.
Where to go next