UDP Sockets (dgram Module)
The dgram module implements UDP — a connectionless, best-effort transport. Unlike TCP, there's no handshake, no connection, no delivery guarantee, and no ordering: you just fire off independent datagrams (packets) and hope they arrive. That sounds worse, but for the right workloads — live video/voice, gaming, telemetry, DNS, service discovery — UDP's low latency and lack of overhead make it the better tool.
UDP vs TCP recap
UDP ( | TCP ( | |
|---|---|---|
Connection | None — send to an address | Handshake first |
Delivery | Best-effort (may drop) | Guaranteed (retransmits) |
Ordering | None | In-order |
Boundaries | Preserved — 1 send = 1 receive | None — byte stream |
Latency | Lower | Higher |
Broadcast/multicast | Supported | Not possible |
A UDP server (receiver)
import { createSocket } from 'node:dgram'
const server = createSocket('udp4') // 'udp4' (IPv4) or 'udp6' (IPv6)
server.on('message', (msg, rinfo) => {
// msg is a Buffer; rinfo tells you who sent it
console.log(`got ${msg} from ${rinfo.address}:${rinfo.port}`)
})
server.on('listening', () => {
const { address, port } = server.address()
console.log(`listening on ${address}:${port}`)
})
server.bind(5000) // listen for datagrams on port 5000A UDP client (sender)
import { createSocket } from 'node:dgram'
const client = createSocket('udp4')
const message = Buffer.from('hello over UDP')
client.send(message, 5000, '127.0.0.1', (err) => {
if (err) console.error(err)
else console.log('datagram sent')
client.close() // no connection to tear down — just release the socket
})Echo example end-to-end
import { createSocket } from 'node:dgram'
// Server: echo each datagram back to its sender
const server = createSocket('udp4')
server.on('message', (msg, rinfo) => {
server.send(msg, rinfo.port, rinfo.address) // reply to the origin
})
server.bind(5000)Broadcast and multicast — UDP-only powers
UDP can send one datagram to many receivers at once — impossible with TCP. Broadcast hits every host on the local subnet; multicast hits only hosts that joined a group address. These power service discovery (mDNS/Bonjour), streaming, and IoT.
import { createSocket } from 'node:dgram'
const socket = createSocket('udp4')
socket.bind(() => {
socket.setBroadcast(true) // enable broadcast
socket.send('ping', 5000, '255.255.255.255') // to the whole subnet
// Multicast: join a group, then send/receive on it
socket.addMembership('239.255.0.1') // join multicast group
})Datagram size and fragmentation
When to choose UDP
Real-time media — voice/video where a late packet is worse than a lost one.
Gaming — frequent position updates; the next one supersedes a dropped one.
Telemetry / metrics — high-volume stats (e.g. StatsD) where occasional loss is fine.
Discovery & DNS — small request/response, broadcast/multicast.
Not for — anything requiring every byte intact and in order (use TCP/HTTP).