DEV Community

Cover image for MUS: "No-Tax" Serialization Format
Yuri Zinchenko
Yuri Zinchenko

Posted on • Originally published at ymz-ncnk.Medium

MUS: "No-Tax" Serialization Format

MUS (Marshal, Unmarshal, Size) is a serialization format founded on the “Keep It Simple” principle. If you are engineering high-performance systems, MUS offers three mechanical advantages that traditional formats don’t:

  • Extreme Density: By eliminating almost all metadata, MUS payloads are often the smallest possible representation of your data.
| NAME     | Bytes  |
|----------|--------|
| MUS      | 58.00  |
| Protobuf | 69.00  |
| JSON     | 150.00 |

Full benchmarks https://github.com/ymz-ncnk/go-serialization-benchmarks
Enter fullscreen mode Exit fullscreen mode
  • The Size Function: The ability to calculate the exact memory required before allocating a buffer, which allows you to:
    • Reuse buffers effectively to minimize GC pressure.
    • Avoid expensive append calls and re-allocations during marshaling.
  • DTM (Data Type Metadata): A one-byte solution for “heavy” features like versioning and interface serialization.

Untyped Serialization

In most cases, the sender (marshal) and the receiver (unmarshal) already agree on the data type they are communicating with. For example, with dedicated REST endpoints like:

http://example.com/api/v1/foo
http://example.com/api/v1/bar
Enter fullscreen mode Exit fullscreen mode

Both sides know exactly which type is being transferred. In this scenario, any type-hinting or metadata in the payload is a redundant “tax”. Knowing the type is enough, even for structured data, because the type definition itself provides the required order of fields.

Example: Struct to Bytes

Consider a simple User struct. In MUS, we don’t store field names like id or age. We only store the raw values in the order they appear in the code.

type User {
  id    int    // Field 1
  age   int    // Field 2
  admin bool   // Field 3
}

// Data: id=42, age=30, admin=true
// MUS Payload (Binary): [84 60 1]
Enter fullscreen mode Exit fullscreen mode

Because the receiver is using the same User definition, it knows that the first Varint it reads is the id, the second is the age, and the final byte is the admin flag. By offloading the “schema” to the application code, the payload remains 100% data and 0% overhead.

Typed Serialization (DTM)

While shared context covers most scenarios, there are cases where we simply don’t know the data type in advance. This is common when the receiver is expecting to receive:

  • One of several completely different types (e.g., an event stream that could be a LoginEvent or a LogoutEvent).
  • One of several versions of the same data structure (facilitating smooth schema migrations).
  • A concrete implementation of an interface.

In these dynamic cases, we use DTM (Data Type Metadata) — a simple prefix added to your payload:

DTM + Data = Typed Data
Enter fullscreen mode Exit fullscreen mode

By reading the DTM first, the receiver can determine exactly which type is coming next. The beauty of this approach is that it maps complex architectural problems onto simple switch logic.

1. Different Types

When incoming data (from a network, a database, or a file) can represent different structures, the DTM acts as the router.

type Foo
type Bar

const FooDTM
const BarDTM

func UnmarshalDifferentTypes(...) {
  dtm = UnmarshalDTM(...)
  switch dtm {
    case FooDTM:
      // unmarshal and handle Foo
    case BarDTM:
      // unmarshal and handle Bar
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Data Versioning

Instead of adding optional fields that bloat your struct, MUS uses explicit versioning. By using DTMs to distinguish between versions, you keep your current data structures clean and move migration logic into an unmarshaling step.

type Foo = FooV2 // current version
type FooV1
type FooV2

// DTMs represent both the type and the version.
const FooV1DTM
const FooV2DTM

func UnmarshalWithVersioning(...) Foo {
  var foo Foo
  dtm = UnmarshalDTM(...)
  switch dtm {
    case FooV1DTM:
      // unmarshal FooV1, migrate to FooV2, assign to foo
    case FooV2DTM:
      // unmarshal FooV2, assign to foo
  }
  return foo
}
Enter fullscreen mode Exit fullscreen mode

3. Interface Serialization

To serialize an interface, each concrete implementation encodes itself as typed data. During unmarshaling, the DTM tells you which specific struct to instantiate.

type Interface
type Impl1
type Impl2

const Impl1DTM
const Impl2DTM

func UnmarshalInterface(...) Interface {
  var intr Interface
  dtm = UnmarshalDTM(...)
  switch dtm {
    case Impl1DTM:
      // unmarshal Impl1, assign to intr
    case Impl2DTM:
      // unmarshal Impl2, assign to intr
  }
  return intr
}
Enter fullscreen mode Exit fullscreen mode

Streaming Support

MUS is naturally streaming-ready. Because the format is a deterministic sequence of fields where every type carries its own size, you don’t need to know the total data length in advance. You can start writing to the wire immediately, field by field.

Processing on the Fly

Once the receiver identifies the type, via DTM or protocol context, it can begin decoding as soon as the first bytes arrive, consuming exactly the right number of bytes per field without any envelope. This enables non-blocking, low-RAM processing for high-throughput systems.

Implementations

At the moment, the MUS ecosystem is focused on the Go programming language. This includes the core serializer, the DTM support modules, and their respective streaming variants.

Because the format is built on a minimalist specification, it is highly portable. If you’re interested in bringing the “no-tax” philosophy to other languages like Rust, C++, or Java, the spec is ready for implementation.

Resources

Conclusion

MUS isn’t trying to be a “JSON killer.” It’s a tool for when you need high performance, minimal payloads, and absolute control over your memory allocations. By moving metadata out of the payload and making “Size” a first-class citizen, MUS lets you write more efficient code without the overhead of heavy frameworks.

Top comments (0)