# go-tools: the repository behind Staticcheck, and why its module is called honnef.co

> Nearly 7,000 stars for a linter that most Go developers only know by one of its four binaries. The repository is more interesting than the tool, because it is also the analysis library nobody is meant to depend on.

**dominikh/go-tools** — Staticcheck - The advanced Go linter

- Repository: https://github.com/dominikh/go-tools
- Website: https://staticcheck.dev
- Stars: 6,915 · Forks: 431
- Language: Go
- License: MIT
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/dominikh-go-tools

## A repository named for a tool, a module named for a person

The repository description is `Staticcheck - The advanced Go linter`, but almost nothing you import from here comes from the path you would guess. The module line in `go.mod` reads `module honnef.co/go/tools`, a personal vanity domain rather than a GitHub URL, so `go get` and `go install` resolve to `honnef.co/go/tools/cmd/staticcheck` and not to a `github.com/dominikh/...` path. The repository is `dominikh/go-tools`, the author is Dominik Honnef, and the two names do not match. Expect to lose a minute to this the first time you go looking for the source behind a stack trace.

The README is short, which is unusual for a project with this much authority, and it opens with a logo, the phrase `The advanced Go linter`, and a sponsor appeal. That sponsor paragraph is the first substantive thing in the file: financial support by private and corporate sponsors is what guarantees the tool's continued development, and the README asks directly that you sponsor if your company relies on Staticcheck. For a linter that runs in other people's pipelines, that dependency is worth naming out loud.

The stated job is narrow. Using static analysis, Staticcheck finds bugs and performance issues, offers simplifications, and enforces style rules. Three categories, and the order matters, because the first is the one that justifies the project's reputation. Most linters in the Go ecosystem are style enforcers that a team can argue with. A tool whose primary output is genuine bugs is a different kind of dependency.

The project is MIT licensed, the default branch is `master`, and topics include `linter`, `linters`, `sponsor`, `static-analysis` and `staticcheck`. Documentation is not in the repository. The README points at staticcheck.dev for the extensive documentation and for a getting-started page, which is where the real configuration reference lives.

## Four binaries in cmd/, only one of which most people use

The README's tool table lists four commands, each living in its own directory under `cmd/` with its own README describing it in more detail. Staticcheck itself is described as Go static analysis detecting bugs, performance issues and much more. The other three are all variations on one idea, and the variations are worth knowing because they are cheap to run and occasionally surprising.

`structlayout` displays the layout of structs, meaning field sizes and the padding between them. `structlayout-optimize` reorders struct fields to minimize that padding. `structlayout-pretty` formats the output of structlayout with ASCII art. So the family is a diagnostic, an automated fix, and a renderer. For a language where structs are passed around by value and copied constantly, wasted padding is a real cost rather than a curiosity, and this is one of the few tools that will show you the number.

The corresponding paths are:

```bash
cmd/staticcheck/
cmd/structlayout/
cmd/structlayout-optimize
cmd/structlayout-pretty
```

What is not in that table is as informative as what is. There is no separate binary for the quickfixes the linter suggests in an editor, and no binary for the SARIF output, even though the repository tree has directories named `quickfix/` and `sarif/`. Those are part of the implementation, reachable through Staticcheck itself rather than as commands.

The tree also shows `staticcheck.conf` at the root, which is the default configuration file, and a `config/` directory that presumably holds the check definitions. Open issues number in the high hundreds, around 578, against roughly 6,900 stars and 424 forks. For a linter that most Go projects enable in CI, that ratio suggests a project where the incoming reports are the work, not the obstacle.

## Installing a release, and what the master branch costs you

The README's recommendation is unambiguous: run released versions of the tools. Releases are git tags, and the README gives the example `2022.1`, a calendar-style version rather than a semver line. Installation is by `go install`, which means the module path again:

```bash
go install honnef.co/go/tools/cmd/staticcheck@2022.1
```

Prebuilt binaries are offered as an alternative, linked from the releases page, for anyone who would rather not have a Go toolchain in the build path. The README defers the details to the getting-started page on staticcheck.dev, which is where the release cadence and the install matrix actually live.

Then there is the master branch, and the README is unusually honest about it. You can run master instead of a release, and while master is usually stable, it may still contain new checks or backwards incompatible changes that break your build. The README puts the consequence in the reader's hands in one sentence: by using the master branch you agree to become a beta tester. That framing matters more than usual for a linter, because a new check appearing in a point release turns a green pipeline red on code nobody touched.

So there are two distinct stability questions and the answers differ. A released version will not gain new checks, which makes CI output reproducible at the cost of lagging behind new Go releases. Master tracks the language, which means you get checks for new APIs and you accept that some of them will not compile yet. The dependency list shows how seriously the project tracks the toolchain: `go 1.26.0` in `go.mod`, and `golang.org/x/tools v0.44.1-0.20260420230617-19499e7caabc`, a dated pseudo-version rather than a tagged release, because static analysis against `go/types` needs the in-development version of the type checker to see new language features.

## The analysis libraries are the real asset, and the README tells you not to use them

The most valuable thing in this repository is not in the tool table. It is the set of packages that implement the analysis: `analysis/` for the framework the checks are written against, `lintcmd/` for the command-line plumbing, `simple/` and `staticcheck/` and `unused/` for the check families themselves, `stylecheck/` for the style rules, `printf/` for the printf and format-string analysis, `quickfix/` for the suggested edits, `sarif/` for the interchange format, `pattern/` for the pattern matcher, `knowledge/` for the accumulated knowledge about standard library APIs, `printf/` again for format strings, and `internal/` and `go/` for supporting code.

That list is a description of a decade of accumulated Go language knowledge. `printf/` in particular corresponds to a category of bug the Go compiler does not catch and that is painful to find by hand, where a format string and the arguments passed to it disagree. `knowledge/` is the part that cannot be reproduced from scratch, because it encodes which standard library functions have which properties across versions.

And the README tells you not to depend on any of it. Unless otherwise noted, none of these libraries have stable APIs, their main purpose is to aid the implementation of the tools, and if you decide to use them you should expect semiregular backwards-incompatible changes. This is an unusually explicit invitation to look but not to link, and it is worth respecting, because analysis packages built on `go/types` and `golang.org/x/tools` inherit every upstream breaking change whether the maintainer intends one or not.

The system requirements section is short and permissive by comparison: Staticcheck can be compiled and run with the latest release of Go, and it can analyze code targeting any version of Go up to that latest release. Being able to lint code that targets an older language version than the toolchain you run is what makes it usable in a repository that supports several Go releases at once.

## A repository organised for generation and benchmarks, not just for building

The tree has some entries that do not belong to a normal Go project, and they explain a good deal about how this one works. At the root sit `add-check.go` and `generate.go`, both Go files with a leading underscore-free name in the module root, which in this layout read as developer commands rather than library code. `generate.go` in a repository with a `knowledge/` package is almost certainly how the standard library knowledge is refreshed, and `add-check.go` is how a new check gets its scaffolding. Both are strong hints that adding a check is a routine, partly automated task here rather than a bespoke project.

`_benchmarks/` with a leading underscore is excluded from the build by Go's own tooling rules, which is the conventional way to keep benchmark input code out of `./...`. Its presence next to `debug/` says that performance of the analysis itself is tracked deliberately, not incidentally. For a tool that runs over entire codebases in CI, analysis speed is a feature users notice.

`dist/` and `website/` sit alongside the code, so the distribution and documentation artifacts are versioned in the same tree as the implementation they describe. `doc/` exists as well, and `.gitmodules` means there are vendored or referenced submodules, plausibly the benchmark corpus. `_benchmarks/`, `debug/` and `dist/` are three directories whose purpose cannot be settled from names alone, and they are the first files to open if you want to understand the development loop rather than the tool.

The dependency list is short, which is a good sign for a static analyser. Beyond the toolchain pins there are `github.com/BurntSushi/toml` for the `staticcheck.conf` configuration format, `github.com/google/go-cmp` for test comparison, and `golang.org/x/exp` plus its `typeparams` package for generics support, along with `golang.org/x/mod` and `golang.org/x/sync`. There is one entry that reads like a piece of housekeeping left in place: `golang.org/x/tools/go/expect v0.1.1-deprecated`, pinned by an explicit path rather than the module root.

## Release tags, a homepage that is not GitHub, and who maintains what

The three most recent releases are `2026.2` on 2026-08-20, `2026.2.1` on 2026-08-21, and a `2026.2rc1` release candidate from 2026-06-25. The sequence tells you the shape of the process: a release candidate roughly two months ahead, a tagged release, then a patch a day later. Two releases within about a day of each other is a slightly unusual cadence, and the patch landing so quickly after the minor release usually means the first tag had a problem worth fixing immediately.

The homepage field is `https://staticcheck.dev`, not the GitHub URL. That single field answers a question the README only answers in passing: documentation, configuration reference, the check list with explanations, and the getting-started guide all live on a separate site rather than in `doc/`. For a tool whose behaviour is a long list of individual checks, that documentation site is the actual product surface, because the README gives you four rows in a table and a link.

The sponsor framing extends across the project's public properties. The repository topics include `sponsor` and `static-analysis` but not `golang` or `go`, which is an odd omission for a Go project and a reasonable one given where the audience comes from. The README links a sponsors page on the project site alongside a GitHub sponsorship profile, so the funding path runs through both.

Ownership is a single-maintainer project with institutional backing, and the README does not pretend otherwise. The sponsor paragraph exists because there is no company behind this. The last push was on 2026-08-24, three days after the 2026.2.1 patch release, so the branch was still moving immediately after that tag.

## Conclusion

Use the released binaries rather than the master branch, install with `go install`, and treat Staticcheck as a finding list rather than a style contract: the checks that fire on code you did not change are usually the ones worth arguing about. The libraries in this repository are a different proposition, and the README says so plainly, with semiregular backwards-incompatible changes as the stated cost of depending on them. Version 2026.2.1 is the current release, the tags follow a calendar version, and the module path `honnef.co/go/tools` will surprise anyone who searched for the GitHub URL instead of the package. Open issues sit around 578, which is high for a project this size and consistent with one that treats incoming reports as the point. The last push was on 2026-08-24.

## FAQ

### How do I install Staticcheck?

The README recommends released versions, installed with go install against the module path: go install honnef.co/go/tools/cmd/staticcheck@2022.1. Prebuilt binaries are linked from the releases page as an alternative. The module path is honnef.co/go/tools rather than a github.com path, which surprises people the first time.

### Should I run Staticcheck from the master branch?

Not for CI. The README says master is usually stable but may contain new checks or backwards incompatible changes that break your build, and puts it plainly: using master means agreeing to become a beta tester. A newly added check can turn a green pipeline red on code nobody changed.

### Can I import the Staticcheck analysis libraries in my own tool?

You can, with the expectation the README sets out. Unless otherwise noted none of these libraries have stable APIs, their purpose is to aid implementing the tools, and semiregular backwards-incompatible changes should be expected. The analysis, lintcmd, quickfix and knowledge packages are the ones other projects sometimes reach for.

### Which Go versions can Staticcheck analyze?

Staticcheck can be compiled and run with the latest release of Go, and it can analyze code targeting any version of Go up to that latest release. That means a repository supporting several Go releases can lint all of them with one installed toolchain.

## Sources

- [dominikh/go-tools on GitHub](https://github.com/dominikh/go-tools)
- [License: MIT](https://github.com/dominikh/go-tools/blob/master/LICENSE)
- [Project website](https://staticcheck.dev)
- [README](https://github.com/dominikh/go-tools/blob/master/README.md)
- [Releases](https://github.com/dominikh/go-tools/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dominikh-go-tools
