Every internet application speaks one of two transport protocols: TCP (Transmission Control Protocol) or UDP (User Datagram Protocol). They make opposite trade-offs: TCP gives you reliability and ordering at the cost of latency; UDP gives you speed at the cost of guarantees. Most internet traffic by volume runs on TCP. Most internet traffic by packet count runs on UDP.
This post compares them at a practical level: what each guarantees, when to choose which, what modern protocols (QUIC, HTTP/3, video, gaming) have done to blur the line, and what to use if you’re designing a new application protocol in 2026.
The Core Difference
TCP
- Connection-oriented. Establishes a session with a handshake before any data flows.
- Reliable. Lost packets are retransmitted. Receiver gets everything the sender sent.
- Ordered. Bytes arrive in the same order the sender wrote them.
- Flow-controlled. Sender slows down if receiver can’t keep up.
- Congestion-controlled. Sender slows down if the network is congested.
UDP
- Connectionless. Send a packet; it’s gone. No setup, no teardown.
- Unreliable. Packets can be lost; the sender never knows.
- Unordered. Packets can arrive in any order.
- No flow control. No backpressure.
- No congestion control. Aggressive senders can swamp a path.
UDP is essentially “IP with port numbers.” TCP is a substantial protocol on top of IP.
When TCP Makes Sense
For most application-level traffic:
- Web (HTTP/1.1, HTTP/2) — Every byte matters; order matters.
- Email (SMTP, IMAP) — Reliable delivery is foundational.
- File transfer (FTP, SCP, BitTorrent over TCP) — Can’t lose bytes.
- Database connections (Postgres, MySQL) — Query/response semantics need reliability.
- SSH — Interactive, byte-stream, reliability-critical.
- API calls (REST, GraphQL over HTTP) — All of the above.
The pattern: anything where you’d be annoyed if a byte got lost in transit.
When UDP Makes Sense
For traffic where speed matters more than perfection:
- DNS — A small query/response. Retrying is faster than maintaining a connection.
- VoIP and video calling — A lost packet is silence/glitch; retransmission is too late anyway.
- Online gaming — Same logic. A lost position update from 50ms ago is useless; just send the latest.
- Streaming media (modern) — Increasingly UDP-based (HTTP/3 over QUIC, WebRTC).
- NTP — Time queries don’t need TCP’s overhead.
- DHCP — Bootstrap protocol; can’t depend on TCP because you don’t have an IP yet.
- Monitoring metrics (StatsD, syslog) — Fire-and-forget; don’t slow down the app to deliver every metric reliably.
The pattern: real-time data, broadcast/multicast, simple request/response, or fire-and-forget.
What TCP Costs
TCP’s reliability and ordering aren’t free:
Handshake latency
Three-way handshake: SYN, SYN-ACK, ACK. One round trip before any data can flow.
Head-of-line blocking
If packet #5 is lost, packets #6, #7, #8 sit in a buffer until #5 is retransmitted. Even if they’re for unrelated streams within the connection, they wait.
Connection state
The OS maintains state for every TCP connection: window sizes, sequence numbers, timers, retransmission queues. Tens of thousands of connections add up.
Slow start
TCP starts conservative and ramps up throughput. The first few KB of a connection are slower than steady-state.
These costs are why modern protocols like QUIC moved off TCP — to retain some of the reliability while avoiding the latency penalties.
What UDP Doesn’t Give You (That You Need to Build)
If you use UDP, you typically need to implement:
- Retransmission if you need reliability.
- Sequencing if you need ordering.
- Flow control if you might overwhelm the receiver.
- Congestion control if you don’t want to be a bad internet citizen.
- Reassembly if your messages are larger than a single UDP packet.
This is one reason “just use UDP” is harder than it sounds. By the time you’ve added everything you need, you might as well have used TCP — unless you have a specific reason to keep the protocol custom.
This is essentially what QUIC is: UDP + reliability + ordering + multiplexing + TLS, all implemented in userspace. Best of both worlds.
QUIC and HTTP/3: The Modern Hybrid
QUIC (the transport under HTTP/3) is UDP-based but provides TCP-like reliability with significant improvements. See HTTP/2 vs HTTP/3 for the broader transport comparison.
Key advantages:
- Faster handshake — 1 RTT including TLS, vs 2-3 for TCP+TLS.
- Per-stream loss recovery — head-of-line blocking is per-stream, not per-connection.
- Connection migration — survives IP changes (Wi-Fi ↔ cellular).
- Userspace implementation — innovation isn’t gated on kernel updates.
By 2026, most major web traffic is HTTP/3 over QUIC over UDP, even though the application semantics are “the same as HTTP/2.” The transport-layer choice has fundamentally shifted under the application’s feet.
Practical Decision Tree
If you’re designing a new protocol or choosing how to send data:
-
Is it request/response that fits in one packet (<1400 bytes)?
- Yes: UDP probably fine. DNS, NTP, simple RPC.
- No: continue.
-
Is reliability required at the protocol level?
- Yes: continue.
- No: UDP. Gaming, VoIP, real-time metrics.
-
Do you need streaming or large bidirectional data?
- Yes, and HTTP semantics fit: use HTTP over TCP or HTTP/3.
- Yes, but custom protocol: TCP, or QUIC if you can afford the implementation complexity.
- No: TCP-based request/response.
-
Do you need low first-byte latency?
- Yes: QUIC.
- No: TCP is fine.
Most production applications in 2026 use HTTP (over TCP or QUIC) and never directly choose. The choice is made for you by the framework.
When You Might Use UDP Directly
A few legitimate uses for raw UDP in 2026:
Custom real-time protocols
Multi-player game servers, financial market data feeds, real-time telemetry. Standard protocols don’t fit; you need full control.
High-volume metric / log shipping
StatsD over UDP. Syslog over UDP. Lose a metric occasionally; don’t slow the producer down.
Discovery and broadcast
mDNS, DHCP, network discovery. Inherently broadcast-style.
Specialized networking
WireGuard, VPN data plane, some tunneling protocols. UDP-based by design.
Behind a higher-level framework
If you’re using a real-time SDK (WebRTC, Photon, custom game-networking libraries), they’re using UDP under the hood, but you’re working with their higher-level API.
TCP and UDP Together
Many applications use both:
- DNS mostly uses UDP for queries. Falls back to TCP for large responses.
- HTTP/3 uses UDP for the data plane (QUIC), but
Alt-Svcdiscovery happens over HTTP/2 (TCP). - WebRTC uses UDP for media (low latency) and TCP/HTTPS for signaling (reliable).
- Game clients often use TCP for matchmaking and UDP for in-game data.
The pattern: TCP for setup and reliable bits, UDP for the real-time payload.
Networking Considerations
Firewall behavior
- TCP is well-handled by virtually every firewall.
- UDP is often more restricted. “Allow specific UDP ports” is common; “allow all UDP” is rare.
- QUIC (UDP/443) is increasingly allowed because HTTP/3 made it mainstream.
NAT behavior
- TCP NAT is straightforward — connection-oriented.
- UDP NAT keeps short-lived mappings (usually 30-300 seconds). Long-lived UDP “connections” need keepalives.
- This is why VoIP / gaming protocols often have explicit keepalive frames.
Performance characteristics
- High-throughput TCP is hard to beat for bulk transfer (file downloads, video streaming pre-QUIC).
- High-throughput UDP requires careful tuning (offload features, ring buffer sizes).
- Many small packets (DNS, NTP) — UDP wins easily; per-packet TCP overhead is significant.
Programming Interfaces
TCP in Node.js
import net from 'node:net'
const socket = net.createConnection({ host: 'example.com', port: 80 })
socket.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n')
socket.on('data', (chunk) => console.log(chunk.toString()))
UDP in Node.js
import dgram from 'node:dgram'
const socket = dgram.createSocket('udp4')
socket.send('hello', 1234, 'example.com')
socket.on('message', (msg, rinfo) => console.log(msg.toString(), rinfo))
The APIs are similar in shape but different in semantics. Most application code never touches these — it goes through HTTP or higher.
TL;DR
- TCP is reliable, ordered, connection-oriented. Default for application data.
- UDP is unreliable, unordered, connectionless. Default for real-time or simple request/response.
- TCP costs: handshake latency, head-of-line blocking, connection state.
- UDP costs: you build everything yourself, or use a higher-level protocol like QUIC.
- QUIC (HTTP/3) combines UDP’s flexibility with TCP-like reliability.
- Most applications use HTTP and don’t choose transport directly.
- DNS, NTP, VoIP, gaming are the canonical UDP use cases.
For most application developers in 2026, the answer to “should I use TCP or UDP” is “use HTTP and let the framework decide.” For the few cases where it matters, the decision tree is short. For the modern transport built on UDP, see HTTP/2 vs HTTP/3; for the related packet-size issues, see MTU and MSS.