Skip to content
Boomspot
  • Home
Loading...
Boomspot

Daily tech news, software development coverage, Apple reporting, and the gear behind modern music making.

TwitterLinkedIn

Browse

  • Categories
  • Tags
  • Authors

Company

  • About
  • Contact

Legal

  • Privacy Policy
  • Terms of Service
  • Unsubscribe

© 2026 Boomspot. All rights reserved.

Built by Boomspot
Updated hourly

AI Content Disclosure: Articles on Boomspot are researched, written, and edited with the assistance of advanced AI systems. We combine software-assisted research with editorial oversight to deliver useful, accurate, and practical technical and music production content. Learn more about our editorial approach.

Browse by Category

Technology675Coding185Linux58SEO57Music Production38Studio Gear38Apple Rumors11

Popular Posts

ROCm or Vulkan for llama.cpp on AMD GPUs? How to Decide

ROCm or Vulkan for llama.cpp on AMD GPUs? How to Decide

8 min read
How to Prepare Shorts for Ask YouTube: A Creator Audit

How to Prepare Shorts for Ask YouTube: A Creator Audit

6 min read
Linux Hot Page Promotion Explained: Where AMD IBS Fits

Linux Hot Page Promotion Explained: Where AMD IBS Fits

8 min read
Is Gibney's Four-Hour Musk Documentary Worth Your Time?

Is Gibney's Four-Hour Musk Documentary Worth Your Time?

5 min read
Speed Up Linux Kernel Compile Time: 7 Practical Fixes

Speed Up Linux Kernel Compile Time: 7 Practical Fixes

8 min read

Recent Posts

Polyphonic vs Channel Aftertouch: Test It in Your DAW

Polyphonic vs Channel Aftertouch: Test It in Your DAW

Nov 3, 2026•7 min
Schedule a Nightly Supabase Edge Function with pg_cron

Schedule a Nightly Supabase Edge Function with pg_cron

Nov 3, 2026•8 min
Synesthesia Music Production Tools: What Actually Helps

Synesthesia Music Production Tools: What Actually Helps

Nov 3, 2026•7 min
How to Audit Third-Party Scripts After the DebugBear Hack

How to Audit Third-Party Scripts After the DebugBear Hack

Nov 2, 2026•8 min
Sell or Hold Jio Shares After Listing? A Worked Example

Sell or Hold Jio Shares After Listing? A Worked Example

Nov 1, 2026•6 min
  1. Home
  2. Coding
  3. Binary Serialization vs JSON: Varints, Tags and Caches
coding8 min read

Binary Serialization vs JSON: Varints, Tags and Caches

The same small object takes 237 bytes as RTON and about 337 as compact JSON (hand-counted). Here is how tags, varints and a string cache work, and when JSON still wins.

S

Staff

November 3, 2026

Reviewed byDorian

Binary Serialization vs JSON: Varints, Tags and Caches

The same small object takes 237 bytes as RTON, the binary format used by Plants vs. Zombies 2, and about 337 bytes as compact JSON. That is a saving of 100 bytes. The JSON figure is a hand count and has not been executed. Is the saving worth losing cat, jq and your browser's network tab?

This piece uses RTON as one worked example of a tag-length-value binary format. The format notes come from the community project RETON, and the sample comes from a write-up of a small RTON decoder. The goal is to help you decide when a binary format earns its complexity and when it doesn't.

The three tricks that make binary smaller

JSON spells everything as text. A tag-based binary format spells each value as a one-byte type tag followed by a payload. RTON starts with the bytes "RTON" and a 32-bit little-endian version, then holds the entries, then an FF end marker and the footer "DONE" (per the write-up above).

Type tags. 01 means true, 00 means false, 24 means an unsigned varint, 81 means a length-prefixed string, 85 opens an object and FF closes it. The reader never guesses, because the tag says how many bytes come next. There are no quotes, colons or commas to scan for.

Varints. Each byte carries 7 payload bits, and the top bit says whether another byte follows. The lowest group comes first.

Hand decode of FE 01: the first byte, FE, has its top bit set, so more bytes follow. Its low 7 bits are 0x7E = 126. The second byte, 01, has a clear top bit, so it is the last, and it contributes 1 shifted left by 7 = 128. The total is 126 + 128 = 254. Any value under 128 fits in one byte.

Signed varints. Tag 25 reads an unsigned varint n, then maps it zigzag-style: even n becomes n/2, odd n becomes -(n+1)/2. So 25 03 gives n = 3, which is odd, so -(3+1)/2 = -2.

A longer one: 25 95 01 gives 0x15 + (1 << 7) = 21 + 128 = 149. That is odd, so the value is -(149+1)/2 = -75. Small negatives stay short.

The string cache. The first time a string appears as a key, it is written with tag 90, a varint length and the bytes, and it joins a numbered table. Later uses are 91 plus the index.

In the sample, 90 08 6f 62 6a 63 6c 61 73 73 defines "objclass" as cache entry 4. The second object recalls it with 91 04. That is 2 bytes instead of 10 in compact JSON (8 letters plus 2 quotes).

Size: where it helps and where it doesn't

The sample is a synthetic object with a version and two items that share keys. By hand count, the compact JSON is 337 bytes. The RTON is 237 bytes, which the write-up's annotated dump confirms. The JSON count was computed by hand and has not been executed. Check it with len(json.dumps(obj, separators=(',', ':'))) before quoting it anywhere.

The split is the interesting part. By the same hand count, the first object takes 130 bytes in RTON against 156 in JSON, because it has to define every string. The second takes 70 bytes against 154, because it mostly recalls keys and values. Nearly all the savings come from repetition.

So the tricks help much less in these cases (an inference from the mechanics, not a measurement): This pairs well with how to shut down dev vms at night: tags, schedule, alerts.

  • Data with few repeated keys, such as one big record.
  • Mostly unique long strings, which cost their raw bytes either way.
  • Large numbers, where a varint can reach 5 bytes for a 32-bit value.

Neither the RETON notes nor the write-up compare RTON against gzipped JSON, so this article makes no claim about how far compression closes the gap. Test it on your own payload.

Readability, tooling and debugging

JSON wins this round easily. You can read it in a log, diff it in git, edit it in any editor and paste it into a bug report. Nearly every language has a mature parser for it.

A tag-based binary format costs you all of that. Here is the start of the second object from the sample dump:

00A1  85              object start
00A2  91 02           key, recall cache[2] = "uid"
00A4  90 05 31 2e 30 2e 32   define cache[19] = "1.0.2"

Without the annotator, you see only hex. Worse, the bytes 91 02 mean nothing on their own. A decoder has to have read every earlier 90 to know that index 2 is "uid". The cache makes the stream stateful, so you can't start reading in the middle.

You also need a spec. The RETON notes mark several tags as uncertain, including tag 21 (an int32 zero with no payload), which the write-up's decoder supports only provisionally. Self-describing JSON has no such gap. Plan on writing your own dump tool, because you'll want it on day one. See full coverage of ai agent strategy for hidden-move games: lobster kombat for additional background.

Parsing safety

Binary parsers do arithmetic on lengths that come from the file, and that is where bugs tend to hide. JSON parsers have their own risks, but a hand-written binary reader has more places to go wrong. The decoder in the write-up shows a short list of safeguards worth copying:

  • Bounds check in one place. Every read goes through a function that checks position plus length against the data size, and raises on truncation.
  • Varint length limit. Stop after 63 bits so a run of FF bytes can't loop forever.
  • Depth limit. Cap nesting at 64 levels so a hostile file can't exhaust the stack.
  • Cache index check. Reject a recall whose index is outside the table.
  • Strict end of file. After the footer, the position must equal the file length, so trailing bytes are an error.
  • Refuse unknown tags. Raise with an offset rather than guessing.

One more is an inference, not something the write-up states: don't preallocate memory from a declared array count or string length until the bounds check passes. Otherwise a tiny file can claim a huge size.

Here is a minimal varint reader with those checks (unexecuted, expected results derived by hand):

def read_uvarint(data, pos):
    result, shift = 0, 0
    while True:
        if pos >= len(data):
            raise ValueError('truncated')
        b = data[pos]
        pos += 1
        result |= (b & 0x7F) << shift
        if b < 0x80:
            return result, pos
        shift += 7
        if shift > 63:
            raise ValueError('varint too long')

## read_uvarint(bytes([0xFE, 0x01]), 0) -> (254, 2)
## read_uvarint(bytes([0xFE]), 0)       -> ValueError: truncated

The failure case matters as much as the success case. If FE is the last byte in the file, the loop wants another byte that doesn't exist. The reader must raise instead of returning a wrong number.

Binary is not security

A file that looks like noise is not protected. RTON itself is only an encoding, and anyone with the format notes can decode it. The game this format comes from also wraps some files in encryption, but that is a separate layer, and this article doesn't cover it.

The write-up makes the key point. A client app that decrypts its own data has to hold the key somewhere on the device. Client-side encryption deters casual reading, but it is not strong protection, and anything that really matters belongs on a server. Choose a binary format for size and speed, not to hide data.

Also read: related topic: how to make layered box-shadow css (plus glass cards)

Side by side

| | JSON | Tag-based binary (RTON as example) | |---|---|---| | Size | Text for everything, keys repeated | Compact numbers and cached keys; biggest wins on repeated structure | | Readability | Human readable | Needs a dump tool and the spec | | Schema | Self-describing | Tags are self-describing, but the cache makes the stream stateful | | Parsing risk | Mature parsers | Hand-written readers need bounds, depth and end-of-file checks | | Tooling | Everywhere | Mostly build your own |

Decision checklist

Stay with JSON if people read or edit the data, if it crosses a public API, if payloads are small or rarely repeat keys, or if you haven't measured a size or parse-time problem. Most config files and web APIs fit here.

Consider binary if you ship large volumes of similar records, such as thousands of objects sharing the same keys, and you control both the writer and the reader. Weigh an existing format with maintained libraries before inventing one. A custom format means you own the spec, the dump tool and the fuzzing.

If you do go binary, build the safeguards in from the first commit. Write hand-computed byte fixtures before the decoder, and keep a text export path for debugging.

For most readers the answer is JSON until a measurement says otherwise. For a closed pipeline with repetitive data, a tag-and-varint format with a string cache can pay off. Just accept the tooling bill, and never mistake the encoding for protection.

Tags

Software DevelopmentCoding Best PracticesOpen-sourceDeveloper ToolsProgramming Languages

Keep reading

Transforming Mobile Devices: AI Chips from Arm for Developers
Coding•4 min read

Transforming Mobile Devices: AI Chips from Arm for Developers

Explore how Arm's AI chips are transforming mobile devices and influencing software development. Insights from Geraint North reveal future trends for developers.

Sep 18, 2025

Secure, Traceable Builds with GitHub and JFrog Integration
Coding•4 min read

Secure, Traceable Builds with GitHub and JFrog Integration

Discover how to integrate GitHub and JFrog for secure, traceable builds from commit to production. Streamline your workflow without switching tools.

Sep 11, 2025

Unlocking ChatGPT Developer Mode: Full MCP Client Access
Coding•4 min read

Unlocking ChatGPT Developer Mode: Full MCP Client Access

Unlock the power of ChatGPT Developer Mode with full MCP client access. Discover how to enhance your coding projects and streamline development.

Sep 11, 2025

More stories for your next project

Get tech, coding, and music production updates in your inbox.

Unsubscribe anytime.