What is CBOR?
CBOR (Concise Binary Object Representation) is an IETF binary data format defined in RFC 8949 (updated from RFC 7049). It shares the same conceptual data model as JSON — maps, arrays, strings, numbers, booleans, and null — but uses a compact binary encoding instead of human-readable text.
Key properties that distinguish CBOR from other binary formats:
- Self-describing — no schema is needed to decode; every value carries its type tag inline.
- Compact — integer values often encode in 1–3 bytes; no string quoting or whitespace overhead.
- Extensible via tags — semantic tags wrap any item to convey dates, UUIDs, bignums, URIs, and more.
- IETF standard — adopted by WebAuthn/FIDO2, COSE, CoAP, CBOR-LD, and many IoT protocols.
CBOR vs JSON vs MessagePack
| Format | Standard | Encoding | Schema required | Tags / types | Typical use |
|---|---|---|---|---|---|
| CBOR | IETF RFC 8949 | Binary | No | Typed + semantic tags | IoT, WebAuthn, COSE, CoAP |
| JSON | IETF RFC 8259 | Text (UTF-8) | No | Stringly-typed | Web APIs, config files |
| MessagePack | None (community) | Binary | No | Typed, no semantic tags | High-throughput RPC, caching |
Size comparison
{"name":"Alice","age":30} is 24 bytes. The equivalent CBOR encoding is 16 bytes — roughly 33% smaller with no loss of information.For an IoT sensor fleet sending millions of small packets per day, that 33% reduction translates directly into lower bandwidth costs, longer battery life, and faster transmission over constrained links such as LoRaWAN or NB-IoT.
CBOR major types
Every CBOR data item begins with a one-byte initial byte whose upper 3 bits identify the major type and whose lower 5 bits carry the additional info (the actual value or length).
| Major type | Name | Description |
|---|---|---|
| 0 | Unsigned integer | Non-negative integer (0 .. 264−1). Values 0–23 fit in the initial byte itself. |
| 1 | Negative integer | Negative integer encoded as −1 − n where n is the unsigned value. |
| 2 | Byte string | Arbitrary binary data. Length in bytes precedes the content. |
| 3 | Text string | UTF-8 encoded text. Length is the byte count of the UTF-8 sequence. |
| 4 | Array | Ordered sequence of data items. Length is the number of elements. |
| 5 | Map | Key-value pairs. Length is the number of pairs. Keys may be any type. |
| 6 | Tagged item | A numeric semantic tag followed by a single wrapped data item. |
| 7 | Float / Simple values | IEEE 754 floats (16/32/64-bit) plus simple values: true, false, null, undefined. |
CBOR semantic tags
Tags (major type 6) annotate any item with a well-known semantic meaning without changing the underlying encoding. The TCBORTag enum covers the most commonly used IANA-registered tag numbers:
| Tag | Constant | Meaning |
|---|---|---|
| 0 | ctTagDateTime | Date/time as an ISO 8601 text string. |
| 1 | ctTagEpochTime | Unix timestamp as an integer or float. |
| 2 | ctTagBignum | Positive bignum encoded as a byte string. |
| 3 | ctTagNegBignum | Negative bignum encoded as a byte string. |
| 21 | ctTagBase64URL | Byte string should be encoded as base64url when converted to JSON. |
| 22 | ctTagBase64 | Byte string should be encoded as base64 when converted to JSON. |
| 32 | ctTagURI | Text string is an absolute URI (RFC 3986). |
| 37 | ctTagUUID | 16-byte string is a UUID (RFC 4122). |
Use cases
IoT / constrained devices — CoAP (Constrained Application Protocol, RFC 7252) mandates CBOR as its payload format. Microcontrollers with 32 KB of RAM can encode and decode CBOR without heap allocation.
COSE — CBOR Object Signing and Encryption (RFC 8152) is the binary equivalent of JOSE/JWT. Used in secure hardware attestation and firmware updates.
WebAuthn / FIDO2 — Browser security key attestation objects and authenticator data are CBOR-encoded. Decoding them requires a full CBOR implementation.
CBOR-LD — A CBOR encoding of JSON-LD linked data that achieves 60–80% size reduction compared to the JSON-LD equivalent.
Concise Problem Details — The binary variant of RFC 7807 problem detail objects uses CBOR to report API errors from constrained servers.
Types
TCBORItem is an opaque integer handle. All CBOR data items are created through constructor functions and freed with FreeItem. The handle is valid until freed; freeing a parent item recursively frees all children.
TCBORItem:
ctUInt(0), ctNegInt(1), ctByteStr(2), ctTextStr(3), ctArray(4),
ctMap(5), ctTag(6), ctFloat(7), ctBool(8), ctNull(9), ctUndefined(10)
API Reference
true or false).ArrayAppend.MapAdd or MapAddStr.TCBORTag).Index.NewText item.Index (insertion order).Index (insertion order).0 if the key is not present.{"sensor": "temperature", "value": 23.5_3}.Code Example
Build a sensor reading map, encode it to CBOR binary, print the byte count and diagnostic notation, then decode and read a field back:
uses cbor;
var
Root, Tags, Tag: TCBORItem;
Data: string;
Decoded: TCBORItem;
begin
Root := NewMap;
MapAddStr(Root, 'sensor', NewText('temperature'));
MapAddStr(Root, 'value', NewFloat(23.5));
MapAddStr(Root, 'unit', NewText('C'));
MapAddStr(Root, 'ts', NewTagged(1, NewUInt(1710000000))); { epoch time }
Tags := NewArray;
ArrayAppend(Tags, NewText('room1'));
ArrayAppend(Tags, NewText('floor2'));
MapAddStr(Root, 'tags', Tags);
Data := Encode(Root);
WriteLn('Encoded: ', Length(Data), ' bytes');
WriteLn('Diagnostic: ', Diagnostic(Root));
FreeItem(Root);
Decoded := Decode(Data);
WriteLn('Sensor: ', GetText(MapGetStr(Decoded, 'sensor')));
FreeItem(Decoded);
end.
Package Info
Install
libcbor-devUbuntu / Debian:
sudo apt install libcbor-devmacOS:
brew install libcbor
API Summary
- NewUInt / NewNegInt
- NewText / NewBytes
- NewFloat / NewBool / NewNull
- NewArray / NewMap
- NewTagged
- ArrayAppend / ArraySize / ArrayGet
- MapAdd / MapAddStr
- MapSize / MapKey / MapValue
- MapGetStr
- Encode / Decode
- GetType
- GetUInt / GetNegInt
- GetText / GetBytes
- GetFloat / GetBool
- GetTag / GetTaggedItem
- Diagnostic / ToHex
- FreeItem
- CBORVersion