Skip to content

An int32 in memory is four bytes whether it holds 3 or three hundred million, but a varint uses one byte for small numbers and adds a byte for every 7 more bits a larger number needs. That's why tags for field numbers 1 through 15 take a single byte.

Only 7 bits of each byte carry the number. The top bit, the most significant one, is a continuation flag. It is set to 1 on every byte except the last, so a decoder reading bytes one at a time keeps going until it reaches a byte whose top bit is 0, which is the last byte of the varint.

The 7-bit groups come out least significant group first. So the groups are in the reverse of the order you would read the number in, and a decoder has to read the whole varint before it knows what value it has. In practice this never matters to you, but it does explain why varints look reversed in a hex dump.

Varint encoding steps
1

Chunk Data

The number gets split into 7-bit groups. A byte has 8 bits, so that leaves the top one free to use as a continuation bit.

Group 1
0000001
Group 0
0010110
2

Reverse & Add MSB Flag

Those groups go out least significant first, which is the little-endian order. Every byte then gets its top bit set to 1, apart from the last one.

Byte 0
10010110
MSBDATA
0x96
Byte 1
00000001
MSBDATA
0x01

Further Reading

  • Delta Encoding in Protobuf

    Storing differences between consecutive values so varints stay small, which shrinks repeated numeric data further.

Next

ZigZag

Why negative numbers are expensive as plain varints and how ZigZag encoding maps signed integers to small unsigned ones for sint32 and sint64.