Skip to content
Episode 48 · Slow in Jakarta

TCP vs UDP (and why QUIC exists)

Monday, 8:30: in Jakarta, the StayHub app takes 3.4 s to open on mobile data and a third of guests give up first. The CDN is working and our servers answer in 40 ms.

The internet loses and shuffles packets. TCP fixes that with care and patience; UDP just sends and hopes. Here's when each wins.

30 min intermediateTCP handshake, ACKs & retransmissionTCP congestion controlHead-of-line blockingWhen to use UDPQUIC & HTTP/3Latency
  1. Problem

    Applications want to send messages across a network that drops, duplicates, delays and reorders packets.

  2. Why the simple system fails

    Raw packets give you none of the guarantees apps assume. But adding every guarantee everywhere makes real-time traffic (calls, games) laggy and handshakes slow.

  3. Engineering concept

    Pick the transport by what your data needs: a reliable ordered byte stream (TCP), or independent datagrams where late data is useless (UDP), or reliable independent streams (QUIC).

  4. Technology

    TCP three-way handshake, sequence numbers, ACKs, retransmission, congestion window; UDP datagrams; QUIC with TLS 1.3 and HTTP/3.

  5. Trade-offs

    Reliability and ordering cost latency and head-of-line blocking; UDP pushes reliability, congestion control and security work onto the application.

01

The problem

2 min
Monday, 8:30. Maya has the Indonesia numbers.
  1. Maya · Product manager
    In Jakarta the app takes 3.4 s to open on mobile data. A third of guests quit first.
  2. Omar · On-call SRE
    Our API answers each call in 40 ms. The CDN serves 96% of photos. Nothing's red.
  3. Lina · Senior engineer, your mentor
    Then look at the road between them. Guess first.
02

The big idea

4 min
Where Jakarta's 3.4 seconds go
The big idea

Round trips are the network's currency. Don't pay for the same handshake six times.

A faster server would save 120 ms of 3.4 s. Moving to Asia is a big project. Paying for the greeting once, then reusing the connection, is cheap. And the choice of TCP or UDP comes down to one question: is late data still useful?

03

How it works

5 min
Two ways to move packets, and one newer one
  1. 1
    Best effort underneath

    Data travels in small packets that can be lost, duplicated or reordered. A round trip (RTT) is one packet there and the answer back: 180 ms Jakarta ↔ Frankfurt.

  2. 2
    TCP: the careful transport

    says hello first (SYN, SYN-ACK, ACK: the , 1 RTT), numbers every byte, resends losses and delivers one ordered stream.

  3. 3
    A new HTTPS call costs 3 round trips

    TCP hello (1) + TLS keys (1) + request and answer (1) = 3 × 180 + 40 ms server = 580 ms. Six in a row ≈ 3.5 s, mostly handshakes.

  4. 4
    Head-of-line blocking

    Head-of-line blocking: one lost packet makes everything behind it on the same TCP connection wait for the resend. On a 2% loss phone, ten photos stall for one.

  5. 5
    UDP: the quick transport

    sends with no hello, no confirmations, no resending. Right when late data is useless (a live call), wrong when every byte matters (a payment).

  6. 6
    QUIC: reliable streams over UDP

    , under HTTP/3, rebuilds reliability over UDP per stream, so a loss only delays its own photo, and folds the TLS hello in: 2 RTT on a new connection.

04

Watch a decision being made

4 min
Worked example

Lina fixes app start for Jakarta

The app takes 3.4 s to open in Jakarta (RTT 180 ms, server 40 ms). Cut it without moving any servers.

  1. 1Count the round trips

    6 calls × 3 = 18 round trips × 180 ms ≈ 3.2 s, plus 240 ms of server work.

    Why: Round trips × RTT is the bill. Count before touching code.

  2. 2Pay for the hello once

    One HTTPS connection kept open (keep-alive, HTTP/2) for all six calls.

    Why: Handshakes are 12 of the 18 round trips; reuse removes 10 of them.

  3. 3Stop waiting in line

    Login first; the five calls after it don't depend on each other, so send them in parallel on the same connection.

    Why: Five in a row cost 5 round trips; together, about 1.

  4. 4Handle the loss, then measure

    Turn on HTTP/3 at the CDN for photos (2% loss). New median: 580 ms + 220 ms ≈ 0.8 s.

    Why: QUIC isolates streams on lossy links. The first call's handshake is now the biggest slice: moving closer is a separate decision.

The whole thing in one line: Lina counted round trips, paid the handshake once and sent independent calls together: 3.4 s became about 0.8 s with the same servers.
05

In real life

3 min
Live video versus recorded video

Zoom: live calls over UDP

  • Publicly documents that media prefers UDP, falling back to TCP/TLS on port 443 when UDP is blocked
  • A late frame is skipped, not waited for
  • Needs its own loss handling and a fallback path

Fits live media, where waiting is worse than losing a frame.

Netflix: recorded video over HTTP and TCP

  • Streams video files over HTTP from its caching servers
  • The player buffers seconds ahead, so a resent packet arrives in time
  • Every byte must be correct

Fits recorded content, where a buffer hides delay.

06

What goes wrong

3 min
Treating a TCP read as one message

Writes are split and merged however TCP likes.

Instead

Frame messages (newline or length prefix), or use HTTP, gRPC or WebSocket.

A new connection per request

Each pays 2–3 round trips of handshakes.

Instead

Keep-alive, connection pools, HTTP/2 or HTTP/3.

"UDP is faster, let's use it for our API"

You'll need reliability anyway, and hand-rolled resends are slower and buggier.

Instead

TCP or QUIC for anything that must arrive complete; UDP where late data is worthless.

07

Trade-offs

3 min
TransportFitsYou pay
TCPAPIs, databases, files: complete and in orderHandshakes; head-of-line blocking
UDPLive media, games, telemetry, DNSNo reliability unless you build it; blocked on some networks
QUIC / HTTP/3Web and mobile on lossy networksMore CPU; needs a fallback; harder to inspect
Tuesday, 10:00. Planning the Asia speed-up.
  1. Karim · CTO
    HTTP/3 is the future. Run it end to end, phone to Frankfurt, this sprint.
  2. Lina · Senior engineer, your mentor
    Our load balancer and tools aren't ready, and some hotel Wi-Fi blocks UDP. Connection reuse gets us 3.4 s to 0.8 s now.
  3. Karim · CTO
    And then we do the migration twice.
08

Your job as tech lead

4 min

Claude Code can write the code for this. You still own the decisions, and you have to know what good looks like to accept or reject its work.

Decisions you own
  • The transport per traffic type: bookings over HTTPS, live voice over UDP, photos over HTTP/3 at the CDN. "UDP is faster" is never a reason alone.
  • The latency budget from far away, counted in round trips, before anyone moves servers.
  • Whether internal services use a real protocol (HTTP, gRPC). Raw TCP means you own message framing.
Tell Claude Code
The StayHub app takes 3.4 s to open in Jakarta: 6 calls in a row, each on a new HTTPS connection to Frankfurt (180 ms round trip, 40 ms server). Don't move servers. First show me where the app creates its HTTP client and count round trips per call. Then propose one shared keep-alive HTTP/2 client, login first, the other five calls in parallel. Don't change the API. Measure start time on a simulated 180 ms, 2% loss network, before and after.
Check before you accept
  • One shared HTTP client instance, not a new one per call.
  • Login first, then the five other calls started and awaited together.
  • The measured median drops from about 3.4 s to about 0.8 s on the simulated link.
Red flags
  • A custom UDP protocol for the API.
  • JSON over a raw TCP socket with no delimiter or length prefix.
  • 0-RTT enabled for requests that change data, which can be replayed.
09

Check yourself

2 min
Q1/3Reasoning
RTT between a guest and your API is 80 ms. On a brand-new connection using TCP + TLS 1.3, how long until the first byte of the HTTP response arrives? Ignore DNS and server processing time.
ms
How confident are you?

Next episode: on Saturday at 00:00 UTC, every guest's browser starts showing "Your connection is not private" on stayhub.com.

Finished?

Mark it complete to update your skill map.

Go deeper (optional)You don't need this to understand the lesson. Open it when a project needs the details: Technical deep dive, Interactive simulation, Visual diagram, Analogy, Check your understanding, Practice ladder, Explain it yourself.
10

Technical deep dive

One connection, and what a loss costs
Worked example

Lina fixes app start for Jakarta

The app takes 3.4 s to open in Jakarta. The API is in Frankfurt (RTT 180 ms) and answers in 40 ms. Cut the start time without moving any servers.

  1. 1Count the round trips

    6 calls × (TCP 1 + TLS 1 + request 1) = 18 round trips × 180 ms ≈ 3.2 s, plus 240 ms of server work.

    Why: Round trips × RTT is the bill. Counting them tells you what's worth fixing before touching any code.

  2. 2Pay for the hello once

    Keep one HTTPS connection open (keep-alive, HTTP/2) and send all six calls over it.

    Why: Handshakes are 12 of the 18 round trips. Reusing the connection removes 10 of them.

  3. 3Stop waiting in line

    The five calls after login don't depend on each other: send them in parallel on the same connection.

    Why: Five calls in a row cost 5 round trips; together, about 1. HTTP/2 multiplexes them on one connection.

  4. 4Check the loss

    Indonesian mobile data loses about 2% of packets. On HTTP/2, one loss stalls every photo on the connection. Turn on HTTP/3 at the CDN for photos.

    Why: On lossy links, TCP's single ordered stream turns one lost packet into a pause for everything. QUIC isolates streams.

  5. 5Measure again

    New median from Jakarta: first call 580 ms + the other five together 220 ms ≈ 0.8 s to open.

    Why: The biggest slice is now the first call's handshakes. Moving that closer to Jakarta is a separate, bigger decision.

The whole thing in one line: Lina counted 18 round trips, paid the handshake once, sent independent calls together, and moved photos to HTTP/3 at the edge: 3.4 s became about 0.8 s with the same servers.

Counting round trips before the first byte of an answer on a new connection (ignoring DNS and server time): TCP + TLS 1.3 = 3 RTT; TCP + TLS 1.2 = up to 4 RTT; QUIC (HTTP/3) = 2 RTT, or the request goes in the first flight with 0-RTT on a repeat visit (only safe for requests that can be repeated, because 0-RTT data can be replayed); a reused connection = 1 RTT.

ts
import net from "node:net";
import dgram from "node:dgram";

// TCP: a stream. Writes may be split or merged; frame messages yourself (newline or length prefix).
const sock = net.connect({ host: "holds.internal", port: 7000 }, () => {
  sock.write(JSON.stringify({ type: "hold", room: 204 }) + "\n");
});
sock.setNoDelay(true); // send small writes at once (request/response protocols)

// UDP: datagrams. Each send is one message, delivered whole or not at all, maybe out of order.
const udp = dgram.createSocket("udp4");
udp.send(Buffer.from(JSON.stringify({ shuttle: 7, lat: -6.2, lng: 106.8, t: Date.now() })), 9000, "telemetry.internal");
// No ACK, no retry: the next position in 1 s makes a lost one irrelevant.
TCP gives you a byte stream with no message boundaries; UDP gives you message boundaries with no delivery guarantee.
11

Interactive simulation

12

Visual diagram

Click a component

One phone, three kinds of traffic. Step through what each transport does.

13

Analogy

  • Sending mailA phone call first: "ready?" "ready!"Sending dataThe TCP handshake
  • Sending mailNumbered registered letters, each signed forSending dataSequence numbers and confirmations
  • Sending mailLetter 5 lost, letters 6 to 20 waitSending dataHead-of-line blocking
  • Sending mailPostcards: cheap, quick, sometimes lostSending dataUDP datagrams
  • Sending mailSeveral vans, each with its own parcelsSending dataQUIC's independent streams

Where the analogy breaks: real letters take days. Network round trips take milliseconds, but a page may need dozens of them, so they add up fast.

14

Check your understanding

Q1/3Decision
Match each workload to the most fitting transport:
POST /bookings with payment details
Voice call with the front desk
Resolving api.stayhub.com
Room photos from a CDN to phones on flaky networks
How confident are you?
15

Practice ladder

Step 1 · Trace

Count the round trips

Estimation Warm-up

A guest in Jakarta (RTT to Frankfurt 180 ms, server work 40 ms) makes one API call. For each case, count the round trips before the first byte of the answer, and the time:

  1. New connection, TCP + TLS 1.3
  2. New connection, TCP + TLS 1.2
  3. New connection, QUIC (HTTP/3), first visit
  4. Reused connection (any protocol)
  5. QUIC with 0-RTT on a repeat visit

Then say which one the fixed app uses for its 2nd to 6th calls.

Step 2 · Complete

Frame the Holds messages

Code Practice

Lina's fixed receiver for the Holds socket has a gap. The sender now ends every JSON message with "\n". Fill in the gap so that split and glued messages are both handled, and explain what buffer is for.

let buffer = "";
sock.on("data", (chunk) => {
  buffer += chunk.toString("utf8");
  // gap: ___
});
Step 3 · Solve

Live shuttle positions

Design Practice

Hotels in Bali want guests to see the airport shuttle moving on a map in the StayHub app. Each shuttle sends its GPS position every second; up to 3,000 guests may watch at once.

  • A position is useless once a newer one exists. Missing one is fine.
  • Guests are on mobile data (about 2% loss) or hotel Wi-Fi, some of which blocks UDP.
  • The app is a mobile app and a website (browsers can't open raw UDP sockets).

Choose how positions travel from the shuttle to StayHub and from StayHub to guests. Justify each, and say what you'd measure to know whether to change it.

Step 4 · Decide

Turn on 0-RTT?

Decision Stretch

The CDN now serves StayHub over HTTP/3 and offers 0-RTT resumption: on a repeat visit, the first request travels with the hello, saving one round trip (180 ms from Jakarta). Its documentation warns that 0-RTT data can be replayed by an attacker who records it.

Karim: "Free speed. Turn it on for everything."

Requests that would benefit: GET /hotels/..., GET /search, but also POST /bookings/:id/pay and POST /reviews.

Write a short decision: "We chose X over Y because…, accepting the risk of…".

16

Explain it yourself

Explain to a product manager why the booking API uses TCP, the video call uses UDP, and the photos are moving to HTTP/3.

0 words