TL;DR:

  • CoAP (RFC 7252) is a UDP-based application protocol designed for microcontrollers and battery-powered sensors where MQTT’s TCP overhead is prohibitive — 4-byte minimum header vs HTTP’s typical 100+ bytes
  • Its REST model (GET, POST, PUT, DELETE with Observe for subscriptions) makes it familiar territory for developers who know HTTP, while running on devices with 2KB of RAM
  • CoAP underpins LwM2M (Lightweight Machine to Machine) — the OMA standard for over-the-air firmware updates and remote device management in IoT fleets

Most IoT discussions centre on MQTT as the default application protocol, and for most connected devices that’s the right choice. MQTT is well-supported, broker infrastructure is mature, and the pub/sub model maps cleanly onto sensor-to-application data flow. But MQTT runs over TCP, and TCP isn’t free: it requires connection state, acknowledgement processing, and a minimum implementation size that not every device can afford.

CoAP exists for the devices that can’t afford TCP.

The Problem CoAP Solves

Consider a coin-cell battery powered temperature sensor. It wakes every fifteen minutes, takes a reading, transmits it, and goes back to sleep. The entire active window needs to be as short as possible to preserve battery life. TCP connection establishment alone — the three-way handshake — adds latency and consumes power before a single byte of sensor data is sent. For a sensor transmitting 20 bytes of data, TCP/MQTT adds tens to hundreds of bytes of overhead.

CoAP uses UDP. There’s no connection to establish. The device sends a packet, optionally with confirmability (which adds a lightweight ACK mechanism), and goes back to sleep. The overhead per message is as low as 4 bytes. A CoAP message carrying a small temperature reading might fit in a single UDP datagram of 30-40 bytes total.

This matters on constrained cellular connections (NB-IoT and LTE-M, where data transmission costs are higher than typical broadband), on LoRaWAN where the maximum payload per transmission is severely limited, and on heavily duty-cycled battery devices where every millisecond of radio activity affects battery life.

The Protocol Structure

CoAP is a REST protocol — it uses the same GET, POST, PUT, DELETE verbs as HTTP and the same concept of resources identified by URIs. A temperature sensor resource might be /sensors/temperature. A GET request retrieves the current reading; a POST might trigger a calibration.

The binary encoding is much more compact than HTTP’s text-based headers. A simple CoAP GET request for a resource is 4 bytes of fixed header plus the URI. An equivalent HTTP request is typically 150-400 bytes for the same operation.

Message types. CoAP has four message types: Confirmable (requires acknowledgement), Non-confirmable (fire and forget), Acknowledgement (response to a Confirmable), and Reset (error response). Most sensor data transmission uses Non-confirmable for efficiency; critical commands use Confirmable.

The Observe option. CoAP Observe (RFC 7641) is the pub/sub equivalent. A client sends a GET with an Observe option to subscribe to a resource. The server then pushes updates to the client whenever the resource changes, without requiring the client to poll. A temperature sensor can push readings when they exceed a threshold; a binary sensor can push immediately on state change. This is the closest CoAP equivalent to MQTT pub/sub.

Block-wise transfer. For payloads larger than a single UDP datagram (RFC 7959), block-wise transfer splits the payload across multiple messages with sequence numbering. This enables firmware image transfer over CoAP, which is essential for OTA updates on constrained devices.

Security. CoAP over DTLS (Datagram Transport Layer Security) provides encryption and authentication equivalent to TLS on TCP-based protocols. A lighter alternative is OSCORE (Object Security for Constrained RESTful Environments, RFC 8613), which provides end-to-end encryption at the message layer rather than the transport layer — meaning OSCORE-protected messages can pass through CoAP proxies and still be encrypted.

CoAP over TCP. RFC 8323 defines CoAP over TCP for scenarios where UDP isn’t available (some corporate firewalls, reliable delivery requirements). This is less common but exists when you need CoAP semantics with reliable transport.

LwM2M: Device Management on CoAP

LwM2M (Lightweight Machine to Machine, from the Open Mobile Alliance) is the fleet management protocol for IoT devices, and CoAP is its transport. Where MQTT handles data messaging well, it doesn’t natively address device management concerns: firmware updates, remote configuration, device registration, monitoring, and command execution.

LwM2M defines a standardised object model for these operations. Devices register with a server, expose a set of objects (Device Information, Firmware Update, Connectivity Statistics, etc.), and the server can read, write, observe, and execute against those objects. OTA firmware updates happen via CoAP block-wise transfer to the Firmware Update object; remote configuration writes to configuration objects.

The LwM2M architecture involves:

  • Bootstrap server: provides initial device configuration (server address, security credentials)
  • LwM2M server: the management plane, handles registration and remote operations
  • Device (client): the constrained device running the LwM2M client library

Common LwM2M implementations:

  • Eclipse Wakaama (C) — lightweight client implementation suitable for RTOS environments, used in many commercial IoT devices
  • Eclipse Leshan (Java) — server implementation, useful for building LwM2M management servers
  • Anjay (C) — AVSystem’s implementation, notably complete and well-tested for commercial deployment

LwM2M servers include AVSystem Coiote, AWS IoT Device Management with LwM2M support, and several LPWAN network operators who offer managed LwM2M services for their NB-IoT and LTE-M customers.

Client Libraries for CoAP

Eclipse Californium (Java) is the most complete CoAP implementation. It supports all CoAP features including block-wise transfer, Observe, DTLS, and CoAP over TCP, and includes an LwM2M implementation (Leshan). It’s suitable for gateway-class devices and server implementations.

libcoap (C) is the standard C implementation for embedded systems. It runs on POSIX systems and various RTOS platforms, and has been ported to Arduino and similar microcontroller environments. The footprint is significant for very constrained devices.

microcoap is a minimal CoAP implementation in C targeting devices with very small RAM. It doesn’t implement the full RFC but handles the core request/response functionality needed for simple sensor scenarios.

aiocoap (Python) is the asyncio-based Python implementation, useful for development, testing, and server-side components. CoAPthon3 is another Python option with a more object-oriented API.

For Arduino/ESP32 environments, several community libraries implement CoAP client functionality, though most lack full RFC compliance and DTLS support.

When CoAP vs MQTT

Use CoAP when:

  • Device has very limited RAM and can’t maintain a TCP stack
  • Battery life requires minimising radio active time
  • Network uses UDP-only transport (some LPWAN backhauls)
  • You need RESTful resource semantics and device management via LwM2M
  • Messages are low-frequency and request-response fits the use case

Use MQTT when:

  • Broker infrastructure is already established
  • High-frequency, many-to-many pub/sub is needed
  • Device can maintain a persistent TCP connection
  • QoS guarantees and retained messages are important
  • The development team knows MQTT and broker tooling well

CoAP and MQTT aren’t mutually exclusive in an architecture. A common pattern is CoAP on the device-to-gateway hop (constrained radio link) with an MQTT gateway translating to MQTT for the gateway-to-cloud hop. Several commercial gateways implement this bridge.

Practical Starting Point

If you’re exploring CoAP for a constrained device project, the fastest way to experiment is with aiocoap or Californium on a development machine. Run a local CoAP server, send requests from a command-line client (coap-client from libcoap, or the coap-cli npm package), and get a feel for the message model before touching embedded code.

For LwM2M fleet management evaluation, the Eclipse Leshan project includes a demo server you can run locally that registers devices and shows their object model — a useful way to understand what LwM2M exposes before committing to a production architecture.