protoc-gen-validate

A protoc plugin that generates polyglot message validators, enforcing constraints Protocol Buffers alone can't express.

Tool
Go
vv1.3.3
4,117stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
59/100Fair
Development Activity16
Maintenance32
Community88
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture78
Code Quality72
Innovation68
Learning Curve75

protoc-gen-validate (PGV) is a protoc plugin that turns declarative constraint annotations on .proto fields into generated Validate() methods for Go, Java, and (partially) C++. Because protobuf’s type system only guarantees shape, not semantics, PGV fills the gap: developers annotate messages with rules like (validate.rules).string.email = true or (validate.rules).uint64.gt = 999, and the plugin emits idiomatic validation code alongside the normal generated message types.

The project is maintained by Buf (originally created at Lyft, later hosted under the envoyproxy GitHub org for module-path stability) and is now in maintenance mode — its authors recommend new projects adopt the successor project, protovalidate, which addresses PGV’s design limitations. PGV nonetheless remains widely deployed across gRPC services, including Envoy itself, and continues to receive maintenance releases.

What You Get

  • A protoc-gen-validate binary that runs as a standard protoc plugin alongside language-native generators
  • A shared validate.proto extension schema defining constraint rules for every protobuf scalar, message, and well-known type
  • Generated Validate() methods in Go, Java, or C++ that raise descriptive errors identifying exactly which field failed which rule
  • Cross-language rule parity — the same .proto annotations produce equivalent validation behavior regardless of target language
  • Support for nested message validation, oneofs, repeated/map fields, and well-known types like Duration, Timestamp, and wrapper types

Common Use Cases

  • Validating incoming gRPC request messages at the service boundary before business logic runs
  • Enforcing field-level constraints (ranges, regex patterns, required nested messages) across polyglot microservices sharing one .proto schema
  • Replacing hand-written boilerplate validation logic in generated protobuf message wrappers
  • Adding email/UUID/pattern validation to API request DTOs generated from protobuf definitions

Under The Hood

Architecture PGV is built on protoc-gen-star (pgs), a framework for writing protoc plugins that hides raw CodeGeneratorRequest handling behind a typed AST of packages, files, and messages. main.go wires up a single module.Validator() module and registers it with pgs.Init(...).RegisterModule(...).RegisterPostProcessor(pgsgo.GoFmt()); module/validate.go’s Module.Execute walks every target file’s messages, calls CheckRules (in module/checker.go) to read the validate.rules/validate.disabled protobuf extensions off each field and message, then dispatches to per-language, per-type Go templates under templates/go, templates/java, and templates/shared to emit the actual validator source. Constraint types themselves are defined once, language-agnostically, in validate/validate.proto and compiled to validate/validate.pb.go, so every target language reads the same rule schema. What breaks if this changes: altering the validate.proto extension numbers or FieldRules oneof shape would require regenerating and re-releasing every language’s templates in lockstep, since Go/Java/C++ all deserialize the identical wire-compatible extension.

Tech Stack The module targets Go 1.24 and depends on github.com/lyft/protoc-gen-star/v2 for the plugin framework and google.golang.org/protobuf for core protobuf runtime types; there are no web/ORM frameworks since this is a codegen tool, not a service. The build is dual-tracked: a Go-native Makefile/go build path for the protoc-gen-validate-go/-java/-cpp binaries under cmd/, and a parallel Bazel build (WORKSPACE, BUILD.bazel files, dependencies.bzl) used for the cross-language conformance harness and CI. Releases are cut via GoReleaser (.goreleaser.yaml) and published as GitHub Releases plus a Java artifact via Maven (.github/workflows/maven-release.yaml).

Code Quality There are no conventional Go _test.go unit tests in the repository; instead, correctness is verified through a custom multi-language conformance harness (tests/harness) that compiles a shared set of annotated .proto test-case files (tests/harness/cases/*.proto) through the Go, Java, and C++ generators and an executor package that runs the generated validators against expected pass/fail fixtures. Code style is enforced via .golangci.yml (gofumpt, gocritic, govet with shadow-checking, misspell), and CI (.github/workflows/ci.yaml) runs on every push. Error handling in the plugin itself favors pgs.Module’s Assert/Fail/CheckErr helpers, which surface plugin misconfiguration as protoc-level failures rather than silently swallowing them.

API Design Developer-facing surface area is intentionally small: a single protobuf extension (validate.rules on fields, validate.disabled on messages) and one lang plugin parameter control all behavior, so integrating PGV into an existing protoc invocation is a one-line addition alongside the language-native generator. The generated Validate() error method follows the same naming/signature convention every consumer already expects from protobuf-generated code, minimizing new API surface to learn. The README is unusually thorough for a codegen tool, documenting every rule type per protobuf field type with runnable examples, though the project’s own maintenance-mode notice steers newcomers toward protovalidate for new work.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search