CLI tool
googleapis/api-linter avatar
googleapis/api-linter

api-linter checks protobuf API surfaces against Google's AIP rules

A linter for APIs defined in protocol buffers.

771 stars183 forksGoApache-2.0

At a glance

What is it?
The Google API Linter is a Go tool that reports common mistakes and inconsistencies in an API surface defined in protocol buffers, using the rules written up as API Improvement Proposals. It is a linter with a deliberate non standard versioning policy, because adding a rule can turn a clean file into a failing one.
Who is it for?
api-linter suits a team defining a gRPC or REST API in protobufs that intends to follow the Google API design guidance, since the rules are the published AIPs and the tool points at the exact field that is wrong. It is the wrong tool if your API is defined in OpenAPI or in another schema, and its version numbers are not a compatibility promise you can rely on.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A linter whose rules are published design documents

The API linter provides real-time checks for compliance with many of Google's API standards, documented using API Improvement Proposals, and it operates on API surfaces defined in protocol buffers. The project description puts it more plainly: a linter for APIs defined in protocol buffers.

The rules are not invented by the linter. They are the AIPs, the public design documents at aip.dev, which cover things like resource naming, pagination, field naming and standard methods. So the tool is a machine checkable encoding of a written style guide, and the link between the two is the rules directory in the repository, where each rule's documentation lives.

The kind of thing it catches is narrow and specific. The README's example is a request message with a field named book where the field should be spelled name:

proto
// Incorrect.
message GetBookRequest {
  // This is wrong; it should be spelled `name`.
  string book = 1;
}

The comment in the example says as much. What makes the tool useful rather than merely pedantic is the second half of that sentence: when it is able to, it also offers a suggestion for the correct fix.

A linter that says only that a field name is wrong leaves the author to guess the convention. One that proposes the right name turns a style guide into a checklist, and that is the difference between a tool people run once and a tool people run in CI.

The project is written in Go, the module path is github.com/googleapis/api-linter/v2, and the licence is Apache 2.0.

The versioning policy is the opposite of semantic versioning

The README has a section on versioning that is worth reading in full, because it changes how you should pin the tool.

The Google API linter does not follow semantic versioning, and the reason given is that semantic versioning is challenging for a tool like a linter, because the addition or correction of virtually any rule is breaking, in the sense that a file which previously reported no problems may now do so.

In place of that, the version numbers refer to the linter's core interface, with a stated policy. Releases with only documentation, chores, dependency upgrades and bugfixes are patch releases. Releases with new rules, or potentially removed rules, are minor releases. Releases with core interface alterations are major releases, and that could include changes to the internal Go interface or to the CLI user interface. There is also an explicit note that releases which increment the Go version count as minor.

The README calls this an attempt to follow the spirit of semantic versioning while still being useful, which is a fair description of a compromise.

The practical consequence is for CI. If a minor release can add rules, then a pipeline that fails the build on any new finding will break on a dependency bump rather than on your code. Pinning the exact version and reviewing the rule list before upgrading is not cautious here, it is the intended usage.

A protobuf-first tool, not an OpenAPI one

The dependency list in go.mod shows what the linter actually reads, and the shape of it says a lot about the scope.

The central dependency is github.com/bufbuild/protocompile at 0.14.1, which is a protobuf compiler implemented in Go. It parses .proto files directly, without shelling out to protoc and without needing the C++ toolchain installed. Alongside it sit google.golang.org/protobuf for the runtime types, and the genproto packages for the Google API annotations, which is where the linter gets the standard method configurations it compares your service against.

Two dependencies point at the domain. github.com/olekukonko/tablewriter is for the human readable output, and github.com/stoewer/go-strcase handles case conversion, which is what a linter that suggests field names needs. github.com/gertd/go-pluralize suggests the linter knows about plural naming conventions, and github.com/bmatcuk/doublestar/v4 is a glob matcher, which is how rules get applied to the files and paths in a repository.

The rules themselves live in the rules directory, with a rules/index.md that indexes the documentation, and the lint and locations directories hold the machinery. There is a cmd directory for the command line entry point and an internal directory for the implementation.

So the tool is about proto files and the Google API conventions. If your API surface is described in OpenAPI, in a GraphQL schema or in a hand written interface definition, there is nothing here for it to read.

Where the rules live and how to read them

The rules directory in the repository is the part of the project most worth reading, and it is documentation rather than only code. The README links the rule documentation at ./rules/index.md, and each rule corresponds to a piece of the AIP corpus, so the linter is effectively a machine readable index into a public style guide.

That has two consequences. The first is that a finding can be looked up and understood, not just suppressed. When the linter reports a field naming problem, the rule document explains the convention and the reasoning, which is the difference between a tool people work with and a tool people mute.

The second is that the rule set is a moving target in a visible way. Each rule addition is a minor release, and each rule is a public document that can be argued with. The repository also has a CONTRIBUTING.md for the contributing guide, a CODE_OF_CONDUCT.md, a SECURITY.md, a CHANGELOG.md and a .release-please-config.json with a manifest, which means the release process is automated through release-please rather than being done by hand.

The project is run from the Google APIs organisation and the documentation site is linter.aip.dev, with the contributing guide at linter.aip.dev/contributing. The last push was on 2026-10-14 and the newest releases are v2.4.0 from 2026-09-10, v2.3.1 from 2026-03-17 and v2.3.0 from 2026-02-10.

What it will not do for you

Three limits are worth being clear about before you wire this into a pipeline.

First, it checks against a specific set of conventions. The AIPs are Google's design guidance, and an API that follows a different house style will produce findings that are correct against the rules and irrelevant to you. There is no indication in the README that the rule set is configurable, so the practical mitigation is to read the rules and decide which ones you accept before you start.

Second, the tool only sees the API surface. It checks the proto, not the implementation, so it cannot tell you that a method is slow, that a field is never populated, or that a resource leaks between tenants. A clean lint run is a statement about naming and shape, not about correctness.

Third, the finding quality depends on the proto being complete. A missing annotation or a hand written descriptor is something the linter cannot judge, and a proto that omits the Google API option annotations will look far cleaner than it is.

The honest summary is that this is a design review tool that happens to run in CI. It is most valuable early in a service's life, when the names are being chosen, and less valuable as a gate once the API is stable and the conventions have settled.

How it differs from a generic proto linter

There are other protobuf linters, and the difference is in what the rules encode.

A general purpose proto linter checks things like field number hygiene, naming conventions for the protobuf language itself, or that required fields are marked required. Those are local rules about the schema language.

The API linter checks rules about the API design itself, derived from the AIPs. The field naming example in the README is the clearest illustration: a message field called book where the convention calls for name is a resource design rule, not a protobuf syntax rule, and no generic linter would know about it.

The comparison with an alternative workflow is worth making as well. The traditional way to enforce a house style across an organisation is a review checklist and a style document. The linter does not replace that, it automates the part of it that can be phrased as a rule about a field name, and the AIP corpus is a ready made source of those rules rather than something a team has to invent.

The limitation of that model is the same one the versioning policy exists to manage. Rules that encode a judgement call will be corrected over time, and every correction changes what a clean file looks like. A team that adopts the rules inherits the churn, and benefits from not having to re-derive the conventions in the first place.

Editorial conclusion

api-linter suits a team defining a gRPC or REST API in protobufs that intends to follow the Google API design guidance, since the rules are the published AIPs and the tool points at the exact field that is wrong. It is the wrong tool if your API is defined in OpenAPI or in another schema, and its version numbers are not a compatibility promise you can rely on. Before adopting it, read the rules index in the repository, run it over one existing proto file to see the false positive rate on your own conventions, and pin the version in CI, because a new minor release can introduce findings that fail your build.

Frequently asked questions

What does the Google API linter check?

It checks API surfaces defined in protocol buffers for compliance with many of Google's API standards, documented as API Improvement Proposals at aip.dev. It identifies common mistakes and inconsistencies, and when it is able to it also offers a suggestion for the correct fix.

How should I version the api-linter in CI?

The linter does not follow semantic versioning, because adding or correcting a rule can make a previously clean file report problems. The version numbers refer to the linter's core interface, and releases that increment the Go version count as minor, so pinning the exact version and reviewing new rules is the intended usage.

What file formats can the api-linter read?

It operates on API surfaces defined in protocol buffers, and it parses .proto files directly through the protocompile library rather than requiring the protoc toolchain. The rules and their documentation are indexed at rules/index.md in the repository.

Official sources

  1. googleapis/api-linter on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/googleapis-api-linter.svg)](https://hysenlabs.com/projects/googleapis-api-linter)

Was this useful?