Protocol Buffer Varint Encoder

Enter an unsigned integer to encode it as a protobuf varint.

Result

ac 02
10101100 00000010
2 bytes

How it is calculated

A protobuf varint stores an unsigned integer in groups of 7 bits, least significant group first. The tool repeats: byte = n & 0x7F, then n = n >> 7; if anything is left in n, the byte gets its top bit set (byte | 0x80), meaning more bytes follow. The loop ends when n is 0. Output shows each byte in hex and in 8-digit binary, plus the byte count. Digits are handled as an exact decimal string, so any value up to 264 − 1 (18446744073709551615, which takes 10 bytes) encodes exactly; larger values give no result. A fraction is cut off (3.9 becomes 3), 0 encodes as one byte 00, and negative or empty input gives no result. This is the plain unsigned varint; it is not the zigzag form used for sint32 and sint64 fields, and not the 10-byte form protobuf uses for negative int32 or int64.

Worked example

Encode 300. In binary 300 is 100101100. Split from the right into 7-bit groups: 0101100 (44) and 10 (2). The first group has more data after it, so its top bit is set: 10101100 = ac. The last group stays 00000010 = 02. Result: ac 02, binary 10101100 00000010, a total of 2 bytes. Decoding reverses it: 0x2c + (2 << 7) = 44 + 256 = 300.

Try this example →

Common mistakes

  • Reading the bytes in the wrong order: the first byte holds the lowest 7 bits, so ac 02 is not 0x02ac.
  • Forgetting that the top bit of each byte is a continuation flag, not data: only 7 bits per byte carry the value, so 128 already needs 2 bytes (80 01).
  • Using this output for a signed field: sint32 and sint64 are zigzag-encoded first, so −1 is not encoded as shown here, and the tool rejects negative numbers.
  • Expecting a field tag: a real message prefixes the value with a tag varint made from the field number and wire type; this tool encodes the number alone.
  • Entering a decimal such as 3.9 and expecting rounding: the fraction is cut off, not rounded.

About this calculator

Protocol Buffers, Google's binary serialization format, encodes integers using base-128 varints to save space on small numbers: each byte carries 7 bits of the value plus a "continuation" bit (the most significant bit) that's set to 1 if more bytes follow and 0 on the final byte. This means small integers — the overwhelming majority in real-world protobuf messages, like field lengths, enum values and IDs — encode in just one byte instead of the four or eight a fixed-width integer would always cost, which is the whole reason protobuf messages stay so compact on the wire.

This calculator takes an unsigned integer and encodes it into its varint byte sequence, showing each byte in both hex and binary so you can see the continuation bits at work. Backend engineers debugging a protobuf wire-format issue, developers writing a custom protobuf parser or serializer without a generated library, and students learning binary encoding schemes use it to manually verify that a value's byte encoding matches what their code produces or expects.

Was this helpful?

You can pick up to 3 reactions.

Comments (1)

  • Editorial team

    The length boundaries are worth memorising when you debug offsets: 127 still fits in one byte (7f), but 128 needs two (80 01), and 16384 is the first value that needs three (80 80 01). So a length prefix that crosses 127 silently shifts every byte after it by one. If you are writing your own parser, which edge case tripped you up first, the continuation bit or the byte order?

Popular calculators

All Calculators