Skip to the content
Software Made Clear Diagrams that show the mechanism About

TCP vs UDP

ANSWER

Use TCP when a missing byte breaks the meaning, and UDP when a late byte is worse than a lost one. TCP guarantees order and delivery by waiting and re-sending; UDP guarantees neither and is finished the moment it hands the packet over.

IN PLAIN TERMS

Think of TCP as a signed-for parcel: the courier waits for a signature, comes back if nobody answers, and the parcels arrive in the order you sent them. UDP is a postcard dropped in a box — cheap, immediate, and nobody tells you if it never arrives.

A few kilobytes should not feel slow, and yet it does. The usual reason is not bandwidth and not the server — it is the handshakes and acknowledgements you are paying for and may not need. Both questions come down to the same fact — TCP buys you order and delivery, and the price it pays is waiting.

CLIENTCLIENTSERVERSERVERTCP — waits for the handshake before sendingUDP — sends immediately, no handshakeSYNSYN-ACKACKDATAno ACK arrivesRESENDDATAlost — no retrytime →
TCP will not send your data until the other end has agreed to receive it; UDP never asks.

What the handshake buys you#

Before a TCP connection carries a single byte of your data, three packets cross the wire: SYN, SYN-ACK, ACK. That round trip is not overhead someone forgot to remove — it is both sides agreeing they can hear each other and settling on starting sequence numbers, so every byte that follows can be placed, counted and confirmed. Nothing is sent until that agreement exists.

An ACK after that point is a narrower promise than it sounds. It means the segment reached the kernel’s receive buffer on the other machine — not that your application has read it, and not that it processed it without error. TCP’s contract ends at the socket. Whether the byte actually did anything useful is a question TCP was never asked and cannot answer.

UDP skips all of it. There is no handshake, no agreed sequence, no socket-level buffer keeping score. A UDP send either leaves the machine or it does not, and the sender is not told either way — which is why the first data arrow in the UDP track above starts the instant you ask, while TCP’s first data arrow waits for three packets to finish.

What re-sending costs when you did not need it#

“Reliable” is usually read as a pure upside, and the cost it hides is head-of-line blocking. TCP must deliver bytes to your application in the order they were sent, so when one segment is lost, every segment that arrived after it — correctly, already sitting in the receive buffer — is held back too. Nothing downstream of the gap moves until the missing piece is resent and arrives. One lost packet stalls the whole stream, not just the byte that went missing.

That resend is automatic and invisible to your code, which is different from a retry your own application decides to issue at the request level. When the network loses a request instead of a packet, the retry is the client’s only option — this article covers what the server owes a request it is seeing for the second time.

UDP has none of this bookkeeping to fall back on. A lost UDP packet is simply gone; nothing behind it waits, and nothing resends it unless your application decides to. That absence is a cost when you needed the data — and free when you did not.

Picking one on purpose#

The trade sits in one place: TCP pays with a handshake up front and a stall whenever a segment is lost, in exchange for never handing your application a gap or an out-of-order byte. UDP pays nothing up front and stalls for nothing, in exchange for making loss and ordering entirely your problem. Neither is the safe default — each is the wrong guarantee to buy for the other one’s workload.

The case that shows it clearest is a live video or game feed carried over TCP. One dropped packet stalls the stream while TCP waits for the resend, so the viewer sees a freeze — and then, when the resend finally lands, a burst of frames arrive all at once, each one older than the moment the viewer is now watching. The resend did its job and delivered the missing data intact. By the time it arrived, that data was worthless: the game had moved on, the video had a newer frame ready, and nobody downstream wanted the stale one anymore. Reliability was the wrong guarantee to buy — the feed needed the freshest packet, not every packet.

This one choice is a small piece of a larger subject: the distributed-systems path is aimed at what the network does to the assumptions you bring to it.

Situation Take Because
A missing byte changes the meaning TCP Order and delivery are the whole point.
A late frame is worse than a lost one UDP Re-sending delivers something already stale.
Many small messages, loss tolerable UDP No handshake, no per-connection state.
You would rebuild acknowledgements yourself TCP You are re-implementing it, worse.

IF YOU REMEMBER ONE THING

TCP and UDP are not a strong choice and a weak one. They are two different answers to “what should happen to a byte that goes missing” — and only your feature knows which answer it needs.

Questions people also ask

5 QUESTIONS
Does TCP guarantee my application received the data?

No. An ACK only confirms the segment reached the receiving kernel's buffer — it says nothing about whether your application has read it yet, let alone processed it correctly. The guarantee stops at the socket, not at your code.

Why is UDP called unreliable if it usually works?

"Unreliable" describes the promise, not the typical outcome. On a healthy path almost every packet arrives; the word just means UDP itself does nothing to notice or fix the rare one that does not, so if that matters to you, you have to build it.

What is head-of-line blocking?

One lost segment forces TCP to hold every segment that arrived after it, even the ones already sitting correctly in the receive buffer, because data has to reach your application in order. The whole stream waits on the one piece that has to be resent.

Does HTTP/3 use TCP or UDP, and why?

UDP, through QUIC, which rebuilds ordering and retransmission itself but keeps them per stream instead of per connection. A lost packet then stalls only the one stream it belongs to, not every request multiplexed alongside it — the exact head-of-line-blocking cost HTTP/2 paid for running over TCP.

Can I get ordering without TCP?

Yes — put a sequence number in each UDP packet and reorder them yourself on arrival, which is what real-time protocols like RTP do. You get ordering without paying for retransmission, because you decide what a late arrival means for your data instead of the transport deciding for you.