Buf CLI

Code linting – Tutorial

Buf offers linting for Protobuf files via the buf lint command in the Buf CLI. In this tutorial, we'll explore how to use linting to maintain code quality and consistency in your projects. Read the overview to learn about editor integration and see usage examples.

Prerequisites

We recommend completing the Buf CLI tour to get an overview of the Buf CLI first.

  • Install the Buf CLI
  • Clone the buf-tour repo:
    $ git clone git@github.com:bufbuild/buf-tour.git
    

1. Inspect the module

Modules represent a collection of files that are configured, built, and versioned as a logical unit when performing Buf CLI operations. The example code provides a module to work with, so start there. From the directory you cloned into, go to the tutorial code:

$ cd buf-tour/start/tutorial-lint

Your module has the directory structure shown below, and is defined by the buf.yaml file in the proto directory (the root of your schemas). This module is your input for the buf lint commands in the rest of the tutorial.

.
└── proto
    ├── buf.yaml
    └── acme
        └── weather
            └── v1
                └── weather.proto

The example buf.yaml file contains all of its required fields. The lint field controls your lint settings. It's set to our recommended default of DEFAULT, which includes every rule we feel is important for modern Protobuf development.

proto/buf.yaml
version: v1
name: buf.build/tutorials/lint
breaking:
  use:
    - FILE
lint:
  use:
    - DEFAULT

For more information about specific fields, see the buf.yaml reference.

2. Run lint

Run buf lint on your module by specifying the filepath to the directory containing the buf.yaml file. It uses the current directory by default, but in the example code the input is the proto subdirectory. You can target it with this command, and should receive the following errors:

~/.../buf-tour/start/tutorial-lint
$ buf lint proto
Output
proto/acme/weather/v1/weather.proto:3: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:3:1:Package name "weather" should be suffixed with a correctly formed version, such as "weather.v1". proto/acme/weather/v1/weather.proto:6:3:Enum value name "SUNNY" should be prefixed with "CONDITION_". proto/acme/weather/v1/weather.proto:6:3:Enum zero value name "SUNNY" should be suffixed with "_UNSPECIFIED". proto/acme/weather/v1/weather.proto:7:3:Enum value name "RAINY" should be prefixed with "CONDITION_". proto/acme/weather/v1/weather.proto:21:19:RPC request type "Location" should be named "GetWeatherRequest" or "WeatherServiceGetWeatherRequest".

3. Fix lint errors

Now that you know what needs to be fixed, you can go through your .proto files and fix them. Let's start with the package name—it should match the directory structure under which the schema lives (relative to the module root), so change the package declaration:

proto/acme/weather/v1/weather.proto
syntax = "proto3";

- package weather;
+ package acme.weather.v1;

If you run buf lint proto again, the first two errors about the package no longer appear. You can work through the rest of the errors in a similar way—the messages provide specific suggestions to help you fix them.

The changes the linter recommends are breaking changes for this package, which illustrates why it's best (if possible) to start linting when you first create your Protobuf files. However, it's not always possible, so we also provide a way to temporarily ignore rules when you first bring your .proto files into Buf—see step 5 below.

4. Customize lint configuration

We generally recommend that you use the DEFAULT category for linting—it represents what we consider to be best practice for Protobuf development. However, if your organization's style has other requirements, you can choose a different category or add and remove individual rules from your configuration.

For example, if your org generally agrees with DEFAULT rules but doesn't want to check for a suffix on service names, you can selectively ignore that rule in the configuration like this:

buf.yaml
version: v1
lint:
  use:
    - DEFAULT
  except:
    - SERVICE_SUFFIX

You can also add individual rules to the more minimal categories if they better match your style. For example, to add only the SERVICE_SUFFIX rule to the BASIC category, you can use this configuration:

buf.yaml
version: v1
lint:
  use:
    - BASIC
    - SERVICE_SUFFIX

5. Temporarily ignore lint errors

There may be times when you want to ignore errors temporarily, such as adding buf lint to an existing project (where fixing lint errors would introduce breaking changes). We've provided a flag to make it simple to ignore them in this case. Once you've fixed everything you want to fix, run this command to get a set of lint settings that you can copy and paste into your buf.yaml file to ignore the remaining errors:

~/.../buf-tour/start/tutorial-lint
$ buf lint proto --error-format=config-ignore-yaml
Output
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

Remember to change your buf.yaml file back to avoid committing the temporary settings.