Skip to content

protoc-gen-pydantic

Define your data schema once in Protobuf. Get validated, type-safe Python models automatically.

protoc-gen-pydantic

If you work with Protobuf APIs in Python, you face a familiar tradeoff: use the raw _pb2 classes — no validation, no editor support — or hand-write parallel Pydantic models and keep them in sync forever. protoc-gen-pydantic generates Pydantic v2 models directly from your .proto files, so your schema stays the single source of truth.

How it works

protoc-gen-pydantic is a protoc plugin written in Go. You run buf generate (or protoc) once, and the plugin reads your .proto files and writes ready-to-use Python files alongside them. After that, code generation is the only step — no runtime dependency on the plugin itself.

flowchart LR
    A["proto/user.proto"] -->|buf generate| B["gen/user_pydantic.py<br/>gen/_proto_types.py"]
    B --> C["from user_pydantic import User"]

Every generated message class inherits from _ProtoModel, a thin base class that overrides model_dump and model_dump_json with ProtoJSON defaults on top of standard Pydantic. See Generated Model API for the full interface.

Basic usage

A single buf generate command turns any .proto file into a ready-to-use Pydantic model:

syntax = "proto3";

package example;

message Item {
  string name     = 1;
  int32  quantity = 2;
  double price    = 3;
}
class Item(_ProtoModel):
    name: str = _Field(default="")
    quantity: int = _Field(default=0)
    price: float = _Field(default=0.0)

The generated model validates inputs immediately — no extra setup, no runtime surprises.

With validation constraints

Add buf.validate constraints to your proto fields, and the generator translates them directly into Pydantic validation:

syntax = "proto3";

package example;

import "buf/validate/validate.proto";

// A user account.
message ValidatedUser {
  // Display name (1–50 characters).
  string name = 1 [
    (buf.validate.field).string.min_len = 1,
    (buf.validate.field).string.max_len = 50
  ];

  // Age in years.
  int32 age = 2 [(buf.validate.field).int32.gte = 0];

  // Contact email address.
  string email = 3 [(buf.validate.field).string.email = true];

  enum Role {
    ROLE_UNSPECIFIED = 0;
    ROLE_VIEWER = 1;
    ROLE_EDITOR = 2;
    ROLE_ADMIN = 3;
  }

  Role role = 4;
}
class ValidatedUser(_ProtoModel):
    """
    A user account.
    """

    class Role(str, _Enum):
        UNSPECIFIED = "UNSPECIFIED"  # 0
        VIEWER = "VIEWER"  # 1
        EDITOR = "EDITOR"  # 2
        ADMIN = "ADMIN"  # 3

    # Display name (1–50 characters).
    name: str = _Field(
        description="Display name (1–50 characters).",
        min_length=1,
        max_length=50,
    )
    # Age in years.
    age: int = _Field(
        default=0,
        description="Age in years.",
        ge=0,
    )
    # Contact email address.
    email: _Annotated[str, _AfterValidator(_validate_email)] = _Field(
        description="Contact email address.",
    )
    role: "ValidatedUser.Role | None" = _Field(
        default=None,
        examples=[1],
    )

The generated model is immediately usable — construct, serialize, and validate with standard Pydantic:

from user_pydantic import ValidatedUser

# Construct and validate
user = ValidatedUser(name="Alice", age=30, email="alice@example.com", role=ValidatedUser.Role.EDITOR)

# Serialize (ProtoJSON — omits zero values, uses original proto field names)
print(user.model_dump_json())
# {"name":"Alice","age":30,"email":"alice@example.com","role":"EDITOR"}

# Validation errors are raised immediately
ValidatedUser(name="", age=-1)  # raises ValidationError (3 validation errors)

Get started →


Acknowledgements

This project is a fork of ornew/protoc-gen-pydantic by Arata Furukawa, which provided the initial plugin structure and plugin options. This fork adds well-known type mappings, Python builtin/keyword alias handling, cross-package references, enum value options, ProtoJSON-compatible output, buf.validate constraint translation, CEL expression transpilation, conditional imports, and a full test suite.