Skip to main content

Command Palette

Search for a command to run...

Why UDP Exists: TCP vs UDP for Developers Who Actually Ship Stuff

Updated
10 min read

Someone on Twitter asked:

Why do we even need UDP? Why not just use TCP for everything?

At first glance, that sounds reasonable. TCP is reliable, ordered and battle tested. UDP feels like the weird cousin that drops packets on the floor and shrugs.

If you write backends, realtime systems, games, VPNs or anything network heavy, this question is not academic. It directly affects latency, correctness and how much protocol pain you sign up for.

Let us walk through this from a programmer’s point of view, keep the details correct, and sprinkle in a few diagrams you can render.

1. Where TCP and UDP actually sit

Both TCP and UDP sit on top of IP. They are siblings, not parent and child.

Think of the stack like this

You can absolutely build a TCP-like protocol on top of UDP, which is what modern things like QUIC effectively do. UDP is the bare transport, you layer your own rules over it.

2. TCP: pretending the network is a reliable pipe

TCP stands for Transmission Control Protocol. Its job is to make an unreliable packet network look like a reliable, ordered byte stream.

From your code’s perspective:

  • You send() bytes.

  • The other side recv()s bytes in the same order.

  • Loss, duplication and reordering are hidden from you.

2.1 Connection setup: the three way handshake

Before real data flows, TCP establishes a connection between two endpoints.

Why this ceremony matters:

  • Both sides agree on initial sequence numbers.

  • Both sides know the other side is reachable.

  • The kernel allocates state for the connection.

You pay one round trip of latency up front, but then you get a nice, reliable stream.

2.2 Reliability and ordering

Inside TCP there is a lot going on:

  • Bytes are numbered with sequence numbers.

  • Receiver sends ACKs for the highest contiguous byte it has seen.

  • If the sender does not see an ACK in time, it retransmits.

  • If packets arrive out of order, TCP buffers and reorders them before exposing data to your app.

You never see packet boundaries in user space. You just see a stream of bytes.

2.3 Error detection and your bank balance

On top of loss and reordering, TCP uses a checksum to detect corruption. If bits flip in flight, the segment is discarded and the sender will eventually retransmit.

That matters for things like:

  • API calls to your bank.

  • Money transfer systems.

  • Anything where changing 100000000 into 1000000 is not acceptable.

You do not want to debug “occasional bit flip in transit” on top of your own code. TCP’s reliability is exactly the kind of boring guarantee you want there.

2.4 Flow control and congestion control

TCP also tries not to melt the network:

  • Flow control makes sure the sender does not overrun the receiver’s buffer.

  • Congestion control tries to detect network congestion and backs off.

You do not configure this in most apps, but you pay for it in latency and variability under packet loss.

3. UDP: fire and forget on purpose

UDP stands for User Datagram Protocol.

It is drastically simpler than TCP:

  • No connection.

  • No handshake.

  • No guarantee of delivery.

  • No guarantee of order.

  • No retransmission.

Each UDP message is a datagram. You send it, and the protocol itself does not care what happens after that.

Sequence for a typical UDP flow:

If a packet is lost or arrives out of order, UDP does nothing. Either your application does not care, or your application is responsible for handling it.

This is not laziness. It is a design decision.

4. TCP vs UDP in real scenarios

Let us ground this in two very different use cases.

4.1 Bank API call: TCP wins, no contest

You call:

GET /balance

and your bank responds with:

{ "balance": 100000000 }

Requirements:

  • Every bit must be correct.

  • You do not care if it took 30 ms instead of 20 ms.

  • You absolutely do not want:

    • Dropped bytes

    • Corrupted digits

    • Mixed responses from two requests

TCP is the obvious choice here. You get ordered, reliable delivery with strong guarantees and mature implementations across every OS and language.

4.2 Live call or stream: UDP shines

Now flip to a live video call.

If a few packets drop:

  • You might miss 50 milliseconds of video or audio.

  • The human brain fills the gap.

  • Retransmitting old frames is pointless, because the moment has already passed.

Here, the priorities are:

  • Keep latency minimal and stable.

  • Deliver fresh data first.

  • Do not stall the entire stream waiting for a lost packet.

That lines up perfectly with UDP plus an application level protocol that can:

  • Mark which frames depend on which other frames.

  • Conceal losses with interpolation or error concealment.

  • Decide when to skip or drop data to stay real time.

5. DNS: critical yet mostly on UDP

DNS is a nice “wait, why?” example.

You type example.com in your browser. Your system sends a DNS query to a resolver and gets back an IP address like 93.184.216.34.

You really care that:

  • The resolver is not lying.

  • The answer arrives correctly.

  • You get an answer quickly, because nothing else happens until DNS is done.

So why is classic DNS mostly UDP based instead of pure TCP?

5.1 Age and constraints

DNS was designed decades ago when:

  • Bandwidth was low.

  • CPU and memory were tight.

  • Network latency was much worse.

A protocol that could handle tiny query and response messages with minimal overhead was extremely attractive.

5.2 Small, latency sensitive messages

Most DNS traffic fits this pattern:

  • Small question.

  • Small answer.

  • One request, one response.

If you had to pay a full TCP handshake for every tiny request, the overhead would be huge relative to the payload.

Remember, DNS lookups often block higher level work:

Until that DNS answer comes back, HTTP cannot even start.

5.3 UDP by default, TCP when needed

The nuance that is often missed:

  • Normal lookups use UDP first.

  • If the response is too large or special operations are needed, DNS can and does use TCP.

You get the speed of UDP in the common case and the reliability of TCP in the less common heavy cases.

6. Using UDP as a building block

Because UDP is so minimal, it is a good foundation for building your own transport with different trade offs than TCP.

Two very relevant modern examples: QUIC / HTTP 3 and WireGuard.

6.1 QUIC and HTTP 3

QUIC is a transport protocol originally built by Google. HTTP 3 runs over QUIC, and QUIC runs over UDP.

High level comparison:

QUIC reimplements many ideas from TCP:

  • Reliability.

  • Ordering.

  • Congestion control.

But it does so with different goals:

  • Better connection migration.

  • Different multiplexing behavior.

  • Integrated encryption as a first class feature.

Key point: QUIC is not “raw UDP”. It is a full featured transport protocol built on top of UDP to avoid being locked into the legacy TCP semantics.

6.2 WireGuard and VPNs over UDP

WireGuard is a modern VPN protocol that typically uses UDP for the tunnel.

You can visualize it like this:

Inside that WireGuard tunnel you run normal TCP or UDP connections. WireGuard itself:

  • Handles encryption and authentication.

  • Tracks session state and replays.

  • Decides how and when to send packets over UDP.

Reliability for your HTTP calls is still provided by the inner TCP connections, not by raw UDP. UDP is used as a flexible, low overhead carrier.

7. The dark side of UDP: spoofing and amplification

UDP’s lack of handshake and connection state makes it simple and fast. It also makes certain attacks easier.

7.1 Spoofing source addresses

With TCP, the three way handshake makes large scale spoofing harder:

  • The attacker has to see replies to complete the handshake successfully.

  • Many spoofed attempts never become fully established connections.

With UDP:

  • There is no handshake.

  • The server will happily send a response to whatever source IP was in the request.

  • That source IP can be forged easily.

The protocol does not verify that the packet really came from where it claims.

7.2 Reflection and amplification attacks

DNS is a common tool for UDP amplification attacks.

  • A sends a small DNS query to B.

  • The source IP is forged to be C.

  • B sends a much larger DNS response to C.

  • C never requested it, but gets flooded.

Multiply that across thousands of resolvers with carefully chosen queries that maximize response size and the victim’s network can be overwhelmed. That is why:

  • Public facing UDP services must be protected.

  • Many setups sit behind Cloudflare or AWS WAF or similar systems.

  • Some networks heavily rate limit or block arbitrary UDP from the internet.

You can technically “disable UDP” at the firewall level to block some of this, but then you break legitimate use cases too. That is why you usually see a combination of:

  • Filtering.

  • Rate limiting.

  • Anycast based absorption of traffic on big providers.

8. How to choose: TCP or UDP in real projects

From a developer point of view, here is a practical way to think about it.

8.1 Choose TCP when

  • You want reliable, ordered delivery.

  • Your application is request response oriented, like most web APIs.

  • You do not want to build or tune your own retransmission and congestion control logic.

  • You are moving money, critical data, binaries, configuration, database traffic and so on.

Examples:

  • Banking APIs and financial systems.

  • Web servers, gRPC over HTTP 2.

  • PostgreSQL, MySQL and other database connections.

  • File transfer, package distribution, updates.

TCP is the default for a reason. It is boring and solid.

8.2 Choose UDP (or protocols built on it) when

  • Latency and smoothness matter more than occasional loss.

  • It is acceptable to drop some packets as long as the stream keeps flowing.

  • You want custom behavior around ordering, retries and buffering.

  • You are willing to implement or adopt a higher level protocol that handles reliability where needed.

Examples:

  • Voice and video calls using WebRTC.

  • Online multiplayer games where the latest state matters more than old updates.

  • Telemetry and metrics where minor loss is acceptable.

  • VPN tunnels like WireGuard.

  • Custom performance sensitive protocols inside your own infrastructure.

A key rule of thumb:

If you do not fully understand what it means to implement a reliable transport, use TCP or an existing UDP based protocol like QUIC or WireGuard. Do not invent your own quasi TCP in production casually.

9. The honest trade off

There is no universal winner.

  • TCP is great when its model aligns with what you need. Reliable, ordered stream, minimal protocol work on your side. It can become a bottleneck when you push hard on latency and custom performance tuning.

  • UDP gives you a simple, minimal building block. It unlocks performance and flexibility, but only if you are prepared to implement the missing pieces correctly and handle the security implications.

The real skill for a programmer is not “picking a side”. It is understanding exactly what guarantees your application needs and matching those to the right layer:

  • Sometimes that is plain TCP.

  • Sometimes it is HTTP 3 over QUIC.

  • Sometimes it is a custom protocol over UDP.

  • Sometimes it is a VPN or tunnel that itself runs over UDP and carries normal TCP inside.

Once you see TCP and UDP as tools with well defined trade offs, the original question flips from:

Why do we even need UDP?

to something much more practical:

Where is TCP doing too much for my use case, and can I safely move those decisions into a higher level protocol built on top of UDP?