Lint a Protobuf workspace#
buf lint checks .proto files against a configurable set of style and structural rules.
This walkthrough takes a workspace that fails several STANDARD rules, fixes the violations, and shows how to either tighten the rule set or carry forward existing violations on a project that’s adopting linting after the fact.
Prerequisites#
- Install the Buf CLI.
-
Clone the examples repository and enter the quickstart’s
startdirectory:
If you’re new to the Buf CLI, work through the CLI quickstart first.
Workspace layout#
buf.yaml sits at the workspace root and declares a single module under proto/:
lint.use in buf.yaml controls which lint rules apply.
It starts at STANDARD, Buf’s recommended default and the strictest of the built-in categories.
version: v2
modules:
- path: proto
name: buf.build/tutorials/lint
lint:
use:
- STANDARD
breaking:
use:
- FILE
See the buf.yaml reference for every field, and the rules page for what each category covers.
Run buf lint#
Run buf lint from the workspace root:
$ buf lint
proto/acme/weather/v1/weather.proto:17:1:Files with package "weather" must be within a directory "weather" relative to root but were in directory "acme/weather/v1".
proto/acme/weather/v1/weather.proto:17:1:Package name "weather" should be suffixed with a correctly formed version, such as "weather.v1".
proto/acme/weather/v1/weather.proto:20:3:Enum value name "SUNNY" should be prefixed with "CONDITION_".
proto/acme/weather/v1/weather.proto:20:3:Enum zero value name "SUNNY" should be suffixed with "_UNSPECIFIED".
proto/acme/weather/v1/weather.proto:21:3:Enum value name "RAINY" should be prefixed with "CONDITION_".
proto/acme/weather/v1/weather.proto:35:19:RPC request type "Location" should be named "GetWeatherRequest" or "WeatherServiceGetWeatherRequest".
The errors fall into three groups: the package name doesn’t match its directory or carry a version suffix, the enum values don’t follow the CONDITION_ / _UNSPECIFIED naming rules, and the RPC request type doesn’t match its method.
Fix the errors#
Change the package declaration so it matches the directory layout under proto/:
syntax = "proto3";
-package weather;
+package acme.weather.v1;
Rewrite the enum so the zero value is named CONDITION_UNSPECIFIED and every other value carries the CONDITION_ prefix:
enum Condition {
- SUNNY = 0;
- RAINY = 1;
+ CONDITION_UNSPECIFIED = 0;
+ CONDITION_SUNNY = 1;
+ CONDITION_RAINY = 2;
}
For the RPC error, the request message needs to be named after the RPC (GetWeatherRequest). Wrap the existing Location message in a new GetWeatherRequest, leaving Location itself in place for callers to populate:
+message GetWeatherRequest {
+ Location location = 1;
+}
+
message Location {
float latitude = 1;
float longitude = 2;
}
service WeatherService {
- rpc GetWeather (Location) returns (GetWeatherResponse);
+ rpc GetWeather (GetWeatherRequest) returns (GetWeatherResponse);
}
Run buf lint again to confirm the workspace is clean:
A silent exit means every rule passes.
Customize which rules run#
STANDARD is the recommended baseline, but you can drop individual rules when they don’t fit your style.
For example, to keep STANDARD but stop checking that service names end in Service:
The reverse also works: pick a smaller category like BASIC and add specific rules from STANDARD on top.
For the full list of categories and rules, see rules and categories.
Ignore errors on existing files#
Adopting buf lint on an existing project is the harder case: many of the changes the linter wants are breaking changes, so you can’t fix them without coordinating consumers.
The standard adoption path is to ignore the violations that exist today, get to a clean lint run, and enforce the rules going forward.
Pair that with buf breaking on every schema change so new edits don’t compound the problem.
buf lint --error-format=config-ignore-yaml emits an ignore_only block scoped to the rules still firing:
$ buf lint --error-format=config-ignore-yaml
version: v1
lint:
ignore_only:
ENUM_VALUE_PREFIX:
- acme/weather/v1/weather.proto
ENUM_ZERO_VALUE_SUFFIX:
- acme/weather/v1/weather.proto
RPC_REQUEST_STANDARD_NAME:
- acme/weather/v1/weather.proto
Two adjustments are needed before pasting this into your buf.yaml:
- Drop the
version: v1line; yourbuf.yamlis already onv2. - Prefix each path with the module’s
path(proto/), since the CLI emits paths relative to the module root butbuf.yamlinterprets them relative to itself.
The result:
version: v2
lint:
use:
- STANDARD
ignore_only:
ENUM_VALUE_PREFIX:
- proto/acme/weather/v1/weather.proto
ENUM_ZERO_VALUE_SUFFIX:
- proto/acme/weather/v1/weather.proto
RPC_REQUEST_STANDARD_NAME:
- proto/acme/weather/v1/weather.proto
Run buf lint once more to confirm a clean state:
Next steps#
- Rules and categories: every built-in lint rule, grouped by category.
- Breaking change quickstart: the natural next check once your schemas pass
buf lint. - Editor integration: surface the same lint errors in your editor as you type.