← Back to DevBytes

Implementing CBOR Format: From Theory to Practice

What is CBOR?

CBOR (Concise Binary Object Representation) is a binary data serialization format defined in RFC 7049. It serves the same purpose as JSON — exchanging structured data between systems — but does so in a compact, binary form. Unlike JSON, which is text-based and must be parsed character by character, CBOR encodes values directly into bytes with a self-describing type system. This makes it highly efficient for constrained environments such as IoT devices, mobile sensors, and embedded systems where bandwidth and processing power are limited.

At its core, CBOR extends the simple data model of JSON (numbers, strings, arrays, maps, booleans, null) with additional native types: byte strings, definite and indefinite length collections, and tags that give semantic meaning to raw values. It also supports 64-bit integers, IEEE 754 floating-point numbers, and binary data without base64‑encoding overhead.

Why CBOR Matters

🚀 Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

Choosing CBOR over JSON or other formats brings concrete benefits in real-world applications:

CBOR Data Model and Encoding Basics

The CBOR byte structure is simple and consistent. The first byte of any data item is divided into two parts: the top three bits encode the major type, and the lower five bits represent additional information. Major types are:

The additional information indicates the length of the payload (for strings, arrays, maps) or the integer value (when it fits in a small range). For example:

This encoding allows small integers to consume just one byte while still supporting up to full 64‑bit unsigned values.

Here’s how a few values are encoded:

0x00            → unsigned integer 0
0x01            → unsigned integer 1
0x18 0xff       → unsigned integer 255
0x19 0x03 0xe8  → unsigned integer 1000
0x20            → negative integer -1 (encoded as -1 - 0)
0x38 0x64       → negative integer -101 (encoded as -1 - 100, with 100 as 0x64)
0x41 0x41       → byte string "A" (length 1, then the byte 0x41)
0x61 0x41       → text string "A" (UTF-8)
0x80            → empty array (length 0)
0x9f            → start of indefinite-length array (ended with 0xff break)

How to Implement CBOR in Your Application

Choosing a Library

Most developers will integrate an existing CBOR library rather than writing a parser from scratch. Popular, well‑maintained implementations include:

These libraries handle all low‑level encoding/decoding, provide APIs for tagged items, and often support streaming. The examples below use cbor2 for Python and cbor for JavaScript.

Encoding Data to CBOR (Python)

First install cbor2:

pip install cbor2

Then encode a Python dictionary containing mixed types:

import cbor2
import datetime

data = {
    "sensor_id": 42,
    "temperature": 23.5,
    "unit": "°C",
    "raw": b'\x01\x02\x03',          # byte string
    "timestamp": cbor2.CBORTag(1, datetime.datetime.now().timestamp())  # epoch tag
}

# Encode to bytes
cbor_bytes = cbor2.dumps(data)
print(cbor_bytes)  # b'\xa5...'

# Encode to hex for inspection
print(cbor_bytes.hex())

Key points:

Encoding Data to CBOR (JavaScript / Node.js)

Install the cbor package:

npm install cbor

Encode a similar object:

const cbor = require('cbor');

const data = {
    sensor_id: 42,
    temperature: 23.5,
    unit: "°C",
    raw: Buffer.from([0x01, 0x02, 0x03]),
    timestamp: new cbor.Tagged(1, Math.floor(Date.now() / 1000))
};

// Encode synchronously to a Buffer
const encoded = cbor.encode(data);
console.log(encoded.toString('hex'));

Note that Buffer is used for byte strings, and cbor.Tagged applies the tag number 1.

Decoding CBOR Data

Decoding is symmetric to encoding. Here’s how to decode in Python:

import cbor2

# Assume cbor_bytes is from the previous example
decoded = cbor2.loads(cbor_bytes)

print(decoded["sensor_id"])   # 42
print(decoded["raw"])         # b'\x01\x02\x03'

# Access tagged value (the timestamp)
tag, epoch = decoded["timestamp"]
print(tag)    # 1
print(epoch)  # e.g. 1712345678.0 (float)

And in JavaScript:

const cbor = require('cbor');

// encoded is the Buffer from earlier
cbor.decodeFirst(encoded, (error, decoded) => {
    if (error) throw error;
    console.log(decoded.sensor_id);       // 42
    console.log(decoded.raw);             // Buffer <01 02 03>
    // The timestamp field will be a Tagged object
    const ts = decoded.timestamp;
    console.log(ts.tag);                  // 1
    console.log(ts.value);                // epoch as number
});

Working with Tags and Extensibility

Tags are a powerful CBOR feature. A tag wraps a data item with an integer identifier that tells decoders how to interpret the value. Standard tags are defined in the IANA CBOR Tag Registry. Some common ones:

When encoding, you explicitly attach a tag. When decoding, the library returns a tagged object (e.g., CBORTag in Python, Tagged in JS). Your application logic can then branch on the tag value to interpret the payload correctly. This allows you to carry semantic meaning without inventing custom envelope structures.

Best Practices for CBOR Implementation

CBOR vs. Other Binary Formats

CBOR sits alongside Protocol Buffers, MessagePack, and Avro. Each has strengths:

For many developers, CBOR hits the sweet spot: it’s compact, schema‑less like JSON, yet binary‑efficient and extensible.

Conclusion

Implementing CBOR in your application bridges the gap between the simplicity of JSON and the performance demands of modern distributed systems. With a solid library, encoding and decoding is as straightforward as working with JSON — just with bytes instead of strings. By understanding the major types, leveraging tags for semantic meaning, and following best practices around canonicalisation and input validation, you can build robust, interoperable components that thrive in constrained environments. Whether you’re building an IoT sensor network, a high‑throughput API, or a cross‑platform mobile app, CBOR is a practical, standardised choice that pays dividends in speed, size, and clarity.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles