buf lint: Enforce Proto Style Rules in CI
buf lint validates .proto files against a rule set (DEFAULT, BASIC, STANDARD, or comments) configured in buf.yaml and exits non-zero on any violation.
buf lint catches naming and structural problems before they reach generated code. It is opinionated but configurable, and gives one annotated line per violation.
What it does
buf lint runs every enabled rule against the module. Rule categories are grouped (MINIMAL, BASIC, DEFAULT, STANDARD, COMMENTS, UNARY_RPC); you select categories and exceptions under lint: in buf.yaml. Each violation prints as path:line:col:message and the command exits 100 (non-zero) if any fire.
Common usage
buf lint
buf lint --path proto/api/v1
buf lint --error-format=github-actions
# buf.yaml
# version: v2
# lint:
# use:
# - DEFAULT
# except:
# - PACKAGE_VERSION_SUFFIXFlags and options
| Flag / config | What it does |
|---|---|
| --path <path> | Lint only the given files or directories |
| --error-format <fmt> | text (default), json, msvs, or github-actions |
| --config <data> | Inline or path config override for buf.yaml |
| lint.use | Categories or rules to enable (e.g. DEFAULT, STANDARD) |
| lint.except | Rules to disable (e.g. PACKAGE_VERSION_SUFFIX) |
| lint.ignore | Files or dirs excluded from linting |
In CI
Run buf lint before buf generate so style is enforced on source, not on generated output. --error-format=github-actions turns each violation into an inline PR annotation. Use lint.ignore for vendored third-party protos you do not control.
Common errors in CI
Typical violations: "Field name "userId" should be lower_snake_case", "Service name "userservice" should be PascalCase", "Files with package "acme.api" must be within a directory "acme/api" relative to root" (PACKAGE_DIRECTORY_MATCH), and "Enum zero value should be suffixed with _UNSPECIFIED". A config error like "Failure: invalid lint rule "FOO"" means a misspelled rule in lint.use.