Reserved Fields and Field Number Management

Manage field numbers and names with reserved declarations. Learn why field number reuse is dangerous, how to deprecate fields safely, and best practices for schema evolution.

Enums & Oneof

Detailed Explanation

Safe Schema Evolution with Reserved Fields

When you remove a field from a protobuf message, you must prevent its field number and name from being reused. Reusing a field number with a different type causes data corruption when old and new code interact.

syntax = "proto3";

message UserProfile {
  // Current fields
  int64 id = 1;
  string username = 2;
  string email = 5;
  string avatar_url = 8;
  bool is_verified = 9;

  // Fields 3, 4, 6, 7 were removed in past versions
  reserved 3, 4, 6, 7;
  reserved "first_name", "last_name", "phone", "address";

  // Ranges are also supported
  // reserved 100 to 199;
}

Why Reserved Matters

Consider this scenario without reserved:

  1. Version 1: string phone = 3; — field 3 is a string containing a phone number
  2. Version 2: Phone field removed, developer adds int32 age = 3; — field 3 is now an integer
  3. A message serialized by Version 1 is read by Version 2: the phone string is interpreted as an integer, causing corruption or crashes

Using reserved 3; prevents the compiler from allowing field number 3 to be reused, catching this error at compile time.

Reserved Names vs. Numbers

  • Reserved numbers prevent wire-level corruption (most critical)
  • Reserved names prevent JSON format conflicts and source code confusion
  • Best practice: reserve both the number and name of every removed field

Field Number Ranges

Field numbers are a finite resource:

Range Purpose
1-15 Single-byte tag encoding — use for frequently accessed fields
16-2047 Two-byte tag encoding — standard fields
2048-536,870,911 Three or more bytes — rarely used
19000-19999 Reserved by the protobuf implementation — cannot use

Deprecation Pattern

Instead of removing fields immediately, mark them as deprecated first:

message Config {
  string name = 1;
  string old_setting = 2 [deprecated = true];
  string new_setting = 3;
}

Use Case

Evolving production protobuf schemas safely in large organizations where multiple service versions coexist, and backward/forward compatibility is essential to avoid data corruption during rolling deployments.

Try It — Protobuf Definition Parser

Open full tool