Networking and API Design for System Design

TCP vs UDP

You're designing a video streaming service and a payment system. One should use TCP, the other might use UDP. Knowing which and why is a core system design decision.


The Concept Explained

TCP and UDP sit at the same layer and make opposite promises.

TCP gives you a connection: bytes arrive, in order, exactly once, or the connection fails. It achieves this with sequence numbers, acknowledgements, retransmission, and congestion control.

UDP gives you datagram delivery and nothing else. No connection, no ordering, no retransmission, no congestion control. A datagram arrives or it does not, and you are not told which.

The instinct is to read this as "TCP is better, UDP is for special cases." The more useful framing:

KEY CONCEPT

TCP's guarantees are not free, and they are not always what you want. Its cost is delay: a connection setup before any data flows, and head-of-line blocking where one lost packet stalls every byte behind it until it is retransmitted. For real-time data, a frame that arrives 300ms late is worse than a frame that never arrives, because your application would rather move on. That is the entire case for UDP.

For the mechanics of the handshake and connection lifecycle with packet captures, the free Networking Fundamentals course covers it hands-on. This lesson is about the design decision.


How It Works

Connection setup as a latency cost

TCP begins with a three-way handshake:

client ── SYN ─────────> server
client <── SYN-ACK ───── server
client ── ACK ─────────> server        one full round trip before any data

One round trip. Add TLS and you pay one or two more before your first byte moves:

new HTTPS connection over a 100ms RTT link

TCP handshake            100ms
TLS 1.3 handshake        100ms
request + response       100ms
                       ------
total                    300ms   for a request the server handled in 5ms

That is the number worth carrying into interviews. Connection setup dominates short requests on high-latency links, which is why connection reuse, keepalive pools, and HTTP/2 multiplexing matter far more than most micro-optimizations (Lesson 1.4), and why an API gateway opening a fresh upstream connection per request is quietly expensive (Lesson 3.1).

Head-of-line blocking

TCP delivers bytes in order. If packet 3 of 10 is lost, packets 4 through 10 may have arrived and the kernel will not hand them to your application until 3 is retransmitted.

sent      1  2  3  4  5  6
arrived   1  2  ✗  4  5  6
delivered 1  2  ................ waiting for 3 ................ 3 4 5 6

For a file transfer this is exactly right: you need all the bytes, and order is essential. For a live video stream it is the wrong behavior, because by the time packet 3 arrives, the moment it belonged to has passed, and packets 4 through 6 were held back for content that is now useless.

This is the precise reason real-time media uses UDP: the application would rather have a small glitch now than perfect data late.

Congestion control, and why loss hurts disproportionately

TCP treats packet loss as a signal that the network is congested and reduces its sending rate accordingly. This is essential for internet stability and it produces a counterintuitive effect:

A 1% loss rate does not cost 1% of throughput. It can cost most of it, because the congestion window collapses and rebuilds repeatedly. Applications that "got slow" with no code change, flat CPU, and a healthy database are frequently suffering packet loss somewhere in the path.

UDP has no congestion control at all, which is a two-sided fact. It will not slow down under loss, and it will also happily contribute to congestion collapse if used carelessly at volume. Anything sending significant traffic over UDP must implement its own rate control, which is a real engineering cost that "just use UDP for speed" ignores.

The comparison

TCPUDP
ConnectionHandshake requiredNone
OrderingGuaranteedNone
ReliabilityRetransmissionNone
Congestion controlBuilt inYours to build
Head-of-line blockingYesNo
Header size20 bytes8 bytes
Multicast/broadcastNoYes
Setup latency1 RTT, plus TLS0 RTT

Choosing, by workload

TCP is correct for: payments and transactions, APIs and RPC, database connections, file transfer, messaging systems, and essentially anything where losing data is unacceptable. If the data must arrive completely and in order, you want TCP and you should not be creative about it.

UDP is correct for: live audio and video, real-time multiplayer game state, DNS queries, metrics and telemetry at volume, and service discovery.

The pattern connecting the UDP cases: the data is either time-sensitive (stale is useless) or self-contained and cheap to retry (one small request, one small response).

DNS is the clearest example of the second kind. A query and a response both fit in a single datagram, so a handshake would triple the cost of the exchange. If a response is lost, the resolver simply asks again. Making DNS reliable would cost more than losing the occasional query (Lesson 1.5).

The streaming case deserves a nuance that distinguishes a good answer from a great one. Live streaming and video calls use UDP, because latency is the requirement and a dropped frame is acceptable. On-demand streaming (Netflix, YouTube) uses TCP over HTTP, because it buffers ahead and cares about quality rather than sub-second latency, and HTTP brings CDN caching, standard infrastructure, and firewall compatibility.

PRO TIP

If asked "TCP or UDP for a video streaming platform," ask which kind. Live and interactive means UDP or WebRTC, where hundreds of milliseconds matter. On-demand means TCP over HTTP with adaptive bitrate and a CDN. Recognizing that the question hides two different systems is worth more than either answer alone.

QUIC: the interesting third option

QUIC is worth raising unprompted because it shows you understand why the tradeoff existed.

QUIC runs over UDP and reimplements the useful parts of TCP in userspace: reliability, ordering per stream, and congestion control. It exists to fix TCP's structural limits without waiting for kernels and middleboxes to change.

What it buys:

  • Independent streams. Loss in one stream does not block others, which removes the head-of-line blocking that still affects HTTP/2 over TCP (Lesson 1.4).
  • Faster setup. Transport and cryptographic handshakes are combined, so a new connection costs one round trip instead of two, and resumed connections can send data with zero round trips.
  • Connection migration. A connection is identified by a connection ID rather than the four-tuple of addresses and ports, so a phone switching from WiFi to cellular keeps its connection instead of resetting it.

The point to make: QUIC is not "UDP because UDP is fast." It is a demonstration that TCP's guarantees and TCP's implementation were separable, and that the parts causing the pain (in-order delivery across independent streams, kernel-bound evolution) could be replaced while keeping reliability.

Operational limits that surprise people

Two TCP realities worth knowing, because they appear as mysterious failures under load:

Ephemeral port exhaustion. Each outbound connection consumes a local port from a range of roughly 28,000 by default on Linux. A service opening many short-lived connections to the same destination can exhaust them and start failing to connect while looking healthy in every other respect. Connection pooling is the fix.

TIME_WAIT accumulation. A closed connection holds its socket in TIME_WAIT for around 60 seconds to ensure late packets are not misattributed. Under high connection churn, tens of thousands of sockets accumulate in that state. It is the same underlying problem as port exhaustion and has the same answer: reuse connections instead of creating them.


System Design Implications

  • This is a latency-versus-completeness decision, and stating it that way immediately frames the answer correctly.
  • Connection reuse is one of the highest-leverage optimizations available, because it removes 1-2 round trips from every request. Any design with high request volume to a fixed set of upstreams should mention pooling.
  • UDP moves work into your application. Choosing it means you own retransmission (if you want any), ordering, and rate control. Budget for that rather than treating it as free speed.
  • Firewalls and middleboxes favor TCP. Many restrictive networks block or aggressively time out UDP, which is why WebRTC needs TURN over TCP as a fallback (Lesson 5.5) and why QUIC deployments keep a TCP path available.
  • Packet loss is a system design concern, not just an ops one. Cross-region and mobile paths lose packets, and TCP's response to loss is what turns a small network problem into a large latency problem.

Tradeoffs and Decision Framework

Reliability versus latency. The core trade. TCP retransmits and delays; UDP delivers what arrives when it arrives.

Kernel-provided versus application-provided guarantees. TCP is battle-tested and free. Building reliability over UDP is correct only when you need something TCP cannot express, such as per-stream ordering or partial reliability.

Compatibility versus capability. TCP works everywhere. UDP and QUIC are faster where permitted and need fallbacks where they are not.

The decision path:

  1. Must every byte arrive, in order? → TCP
  2. Is stale data worthless? → UDP, or WebRTC for browser media
  3. Is the exchange small, self-contained, and cheaply retried? → UDP (DNS-shaped)
  4. Do you want TCP's guarantees without head-of-line blocking across streams? → QUIC
  5. Unsure? → TCP. It is the right default, and the burden of proof is on UDP.

Common Mistakes

"UDP is faster" as a justification. It is faster because it does less. If you need what TCP does, you will rebuild it worse.

Ignoring connection setup cost. Two to three round trips before data flows, repeated on every new connection.

Treating all video as one workload. Live and on-demand have opposite requirements.

Using UDP at volume without rate control. You become the congestion.

Assuming UDP passes through every network. Restrictive firewalls block it, which is why fallbacks exist.

Expecting loss to degrade throughput linearly. Congestion control makes small loss rates very expensive.

Not pooling connections. Leads to ephemeral port exhaustion and TIME_WAIT buildup under load.


INTERVIEW QUESTION

You're designing a live video streaming platform. Would you use TCP or UDP, and why? What are the tradeoffs?