Skip to main content
When you publish Protobuf messages, the raw serialized bytes often need a small binary header — a prefix — prepended before the payload so consumers can identify the message type and deserialize it correctly. Devset’s wireFormat block on a stage lets you configure exactly how that prefix is constructed, giving you compatibility with Confluent Schema Registry and other binary framing conventions without writing any custom serialization code.
The wireFormat block only applies when the workflow’s contentType is "application/x-protobuf". It has no effect on JSON payloads.

What Wire Format Does

A wire format prefix is a short sequence of bytes placed at the front of every outbound binary message. Its purpose is to tell the consumer which schema or message type to use when deserializing the payload. Confluent Schema Registry, for example, expects a 2-byte message type prefix followed by the serialized Protobuf bytes. Without the correct prefix, your consumer will fail to decode the message. Devset supports two strategies for generating the prefix value:
  • messageType — automatically use the type ID derived from the stage’s schema. This is the standard approach for Confluent Schema Registry compatibility.
  • messagePrefix — write a fixed integer value you provide. Use this when your consumers expect a hard-coded identifier rather than a schema-resolved one.

wireFormat Block Fields

wireFormat.type
"binary-prefix"
required
The framing strategy to apply. Currently the only supported value is "binary-prefix", which prepends a fixed-width integer to the serialized payload.
wireFormat.prefix.size
integer
required
The byte length of the prefix. The only accepted value is 2 (two bytes, supporting values 0–65535).
wireFormat.prefix.source
"messageType" | "messagePrefix"
required
How the prefix value is determined.
  • "messageType" — Devset resolves the type ID from the stage’s schema (via schemaId or the workflow-level default) and writes that integer as the prefix. This is the correct setting for Confluent Schema Registry compatibility.
  • "messagePrefix" — Devset writes the integer you provide in prefix.value as the prefix. Use this for consumers with a fixed or manually assigned type identifier.
wireFormat.prefix.value
integer (0–65535)
The fixed prefix value to write. Only used when prefix.source is "messagePrefix". Must be an unsigned integer in the range 0–65535.

Examples

Using messageType — Confluent Schema Registry

This is the most common configuration. Devset resolves the integer type ID from the stage’s schema and writes it as a 2-byte prefix, matching the Confluent Schema Registry wire format:
{
  "stage": "order-created",
  "event": "order-created",
  "schemaId": "order-created",
  "emit": true,
  "set": {
    "id":     { "$fn": "uuid()" },
    "amount": { "$fn": "int(10, 500)" }
  },
  "wireFormat": {
    "type": "binary-prefix",
    "prefix": {
      "size": 2,
      "source": "messageType"
    }
  }
}
The outbound message is structured as:
[ 2-byte type ID ][ serialized Protobuf payload ]
Your consumer reads the first two bytes to look up the message descriptor, then deserializes the remainder.

Using messagePrefix — Fixed Custom Prefix

When your consumers expect a specific hard-coded identifier rather than a schema-resolved one, use messagePrefix and supply the value directly:
{
  "stage": "payment-processed",
  "event": "payment-processed",
  "emit": true,
  "set": {
    "paymentId": { "$fn": "uuid()" },
    "amount":    { "$fn": "int(100, 5000)" }
  },
  "wireFormat": {
    "type": "binary-prefix",
    "prefix": {
      "size": 2,
      "source": "messagePrefix",
      "value": 42
    }
  }
}
Every message produced by this stage will begin with the two-byte prefix 0x002A (decimal 42), regardless of the schema ID.
When using messagePrefix, make sure the value you choose matches what your consumer expects. Mismatched prefix values cause deserialization failures that can be difficult to debug.

Per-Stage vs Workflow-Level Configuration

The wireFormat block is configured per stage. This design lets different stages in the same workflow use different framing strategies — for example, one stage publishing with a schema-resolved prefix and another with a fixed custom prefix. If every stage in your workflow uses identical wire format settings, you can reduce repetition by defining the wireFormat block in a shared stage template or by copying the block consistently across stages. There is no workflow-level wireFormat shorthand today, but per-stage configuration gives you maximum flexibility for mixed-schema pipelines.
{
  "id": "multi-type-flow",
  "messageType": "kafka",
  "contentType": "application/x-protobuf",
  "topic": "events.all",
  "pipeline": [
    {
      "stage": "user-registered",
      "schemaId": "user-registered",
      "emit": true,
      "set": { "userId": { "$fn": "uuid()" } },
      "wireFormat": {
        "type": "binary-prefix",
        "prefix": { "size": 2, "source": "messageType" }
      }
    },
    {
      "stage": "order-placed",
      "schemaId": "order-placed",
      "emit": true,
      "set": { "orderId": { "$fn": "uuid()" } },
      "wireFormat": {
        "type": "binary-prefix",
        "prefix": { "size": 2, "source": "messageType" }
      }
    }
  ]
}
If you are unsure which prefix strategy to use, start with messageType. It is the correct setting for any broker stack that uses Confluent Schema Registry, which is the most common Protobuf deployment pattern for Kafka.

  • Stage Fields — full reference for the wireFormat field and all other stage-level configuration.
  • Workflow DSL — setting contentType to "application/x-protobuf" at the workflow level.