reviewdog posts linter findings only where the diff touches, one host per run
Automated code review tool integrated with any code analysis tools regardless of programming language.
At a glance
- What is it?
- A Go tool that reads linter output from stdin, keeps the findings that fall inside a patch, and posts them to GitHub, GitLab or Bitbucket. Cheap to adopt when your linters already print parseable lines, and quietly blind to everything else in the file.
- Who is it for?
- reviewdog fits teams that already run linters in CI and want the findings attached to the lines a reviewer is reading; it does not work as a standalone quality gate, since a violation outside the diff is never reported. Before adopting it, confirm that each tool writes lines reviewdog's errorformat can match, or a SARIF file it can parse, pick the single host you will post to, and check that the commit your install URL pins still matches the release you mean to run.
- Can I use it commercially?
- Yes. MIT 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 received new commits within the last day.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- reviewdog/reviewdog9,743 ★ · +254
| Repository | 2026-07-31 | 2026-11-13 |
|---|---|---|
| reviewdog/reviewdog | 9.5k | 9.7k |
254 Stars in the last 105 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Four install paths, each freezing a different commit or toolchain
The quickest route pipes a remote script into a shell, and the URL is pinned to a commit rather than to a tag or a branch:
# Install the latest version. (Install it into ./bin/ by default).
$ curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/fd59714416d6d9a1c0692d872e38e7f8448df4fc/install.sh | sh -s
# Specify installation directory ($(go env GOPATH)/bin/) and version.
$ curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/fd59714416d6d9a1c0692d872e38e7f8448df4fc/install.sh | sh -s -- -b $(go env GOPATH)/bin [vX.Y.Z]The pin is the point and also the problem. A script fetched from a fixed commit cannot change under you, which is what you want from a shell pipe, but it also never moves: to take a new release you edit the URL yourself. The second form is the only place a version is expressed, and it is a placeholder the reader fills in. macOS and Linux users have a package manager path:
$ brew install --cask reviewdog/tap/reviewdog
$ brew upgrade --cask reviewdog/tap/reviewdogWindows is documented as scoop install reviewdog, and the Alpine note explains that curl is absent there so wget is the fallback. Go developers skip the binary entirely:
$ go install github.com/reviewdog/reviewdog/cmd/reviewdog@latestThat one resolves through the module proxy and lands in $(go env GOPATH)/bin, so it needs a toolchain new enough for the go 1.26.0 line that go.mod declares. Two of these paths pin a commit and one tracks the newest module version, so a workstation and a CI image built on different days can disagree about which reviewdog is on the PATH.
The integration contract is a line-based format, not structured output
reviewdog does not run your linter. It reads what the linter printed and matches each line against a pattern borrowed from Vim's quickfix parser, reviewdog/errorformat. Four directives carry most of the weight: %f for the file name, %l for the line number, %c for the column, and %m for the message, with %% standing for a literal percent sign. For output shaped as `{file}:{line number}:{column number}: {message}` the pattern is `%f:%l:%c: %m`, passed with -efm:
$ golint ./...
comment_iowriter.go:11:6: exported type CommentWriter should have comment or be unexported
$ golint ./... | reviewdog -efm="%f:%l:%c: %m" -diff="git diff FETCH_HEAD"The table of contents also carries separate sections for RDFormat, diff, checkstyle and SARIF input, which is how tools that already emit machine-readable reports get connected instead of hand-parsed. Anything the errorformat syntax cannot express is simply not a finding for reviewdog. The README points at reviewdog/errorformat and the Vim errorformat manual for complex shapes, so the cost of an awkward tool falls on you as pattern-writing work rather than as a switch.
Findings outside the patch are dropped, so a clean run says nothing about the file
The filtering is the product. reviewdog uses the output of lint tools and posts a comment only when the finding lands in the diff of the patch under review, and the same filtering runs in the local environment. The example above hands the patch in explicitly with `-diff="git diff FETCH_HEAD"`, which makes the boundary visible: reviewdog does not decide what to review, you do, by way of a git command. That has two consequences worth planning for. First, a violation that predates the branch is invisible in the review, so a file full of problems can carry a green check on every pull request, and the tool cannot be used as a health metric for a codebase. Second, the patch you pass is the coverage you get. The repository splits this work across a diff/ package and a filter/ package, and the table of contents closes with separate sections for exit codes and filter mode. Treat the diff command as part of the linter definition, because that is the role it ends up playing.
Nine reporters, one per run, and a Gitea client with no reporter to use it
Delivery is a single flag rather than a list, and the table of contents names nine values: local, which is marked as the default, github-pr-check, github-check, github-pr-review, github-annotations, github-pr-annotations, gitlab-mr-discussion, gitlab-mr-commit, and bitbucket-code-report. Each one posts to a different host surface, so a repository mirrored to two forges cannot be served by a single run; you either accept half the coverage or run reviewdog twice with different flags. The Go module shows what each host costs in dependencies: go-github/v93 for GitHub, ghinstallation/v2 for GitHub App authentication, gitlab.com/gitlab-org/api/client-go/v3 for GitLab, reva2/bitbucket-insights-api for Bitbucket Code Insights, and gitea.dev/sdk. That last one is the awkward entry. A Gitea SDK is required and compiled into the binary, yet no Gitea reporter appears in the documented list, so a team hosting on Gitea has no published flag to reach while the code that talks to Gitea is already being shipped.
Six CI integration paths and one generic path you wire by hand
The supported CI list is longer than the reporter list, which tells you something about where the friction sits. GitHub Actions, Travis CI, Circle CI, GitLab CI and Bitbucket Pipelines each get their own section, then a Common entry covering Jenkins and local runs, with a further subsection for Jenkins combined with the GitHub pull request builder plugin. The repository carries the matching configuration for several of them at once: .travis.yml, .gitlab-ci.yml and a .circleci/ directory sit at the top level. The Common entry covers anything else. The README's own badges point at GitHub Actions workflows running on master for Go tests, for reviewdog itself, and for releases, so the maintainers' own pipeline is the GitHub Actions path.
reviewdog is pointed at its own repository, through textlint and revive
The tree contains .reviewdog.yml, .revive.toml and .textlintrc, plus a package.json and a package-lock.json whose devDependencies are @microsoft/eslint-formatter-sarif ^3.0.0, textlint ^15.0.0, textlint-rule-common-misspellings ^1.0.1, textlint-rule-no-dead-link ^6.0.0 and textlint-rule-write-good ^2.0.0. Read together, they say the project checks its own prose and its own Go code, and that @microsoft/eslint-formatter-sarif is a devDependency. Two practical consequences follow for anyone adopting the same setup. Checking documentation text needs a Node toolchain alongside whatever runs the Go or compiled linters, so a CI image has to carry both. And textlint-rule-no-dead-link means links in your docs are linted. The repository also keeps cienv/, scripts/, _testdata/ and a proto/ directory.
Release tags left a year gap, and the pinned URLs never notice
The published releases are v0.21.2 on 2026-09-18, v0.21.1 on 2026-09-13, and v0.21.0 on 2025-09-03. The gap between v0.21.0 and v0.21.1 is a year and ten days, followed by two tags five days apart, and the last push to the default branch master is dated 2026-11-02. The repository has a CHANGELOG.md; read it before jumping across that gap. The project is MIT licensed and publishes from GitHub Actions with goreleaser, and there is a separate nightly channel with its own repository and its own install script pinned to commit 30fccfe9f47f7e6fd8b3c38aa0da11a6c9f04de7, so you can take a build that is newer than any tag if you accept that nothing about it is released. Choose one channel and pin it. Switching between the curl URL, the brew cask, go install @latest and the action input means four different notions of current.
Editorial conclusion
reviewdog fits teams that already run linters in CI and want the findings attached to the lines a reviewer is reading; it does not work as a standalone quality gate, since a violation outside the diff is never reported. Before adopting it, confirm that each tool writes lines reviewdog's errorformat can match, or a SARIF file it can parse, pick the single host you will post to, and check that the commit your install URL pins still matches the release you mean to run.
Frequently asked questions
reviewdog vs danger
Compare against its own contract: reviewdog reads linter output from stdin, parses it with errorformat, and posts the findings that fall inside the diff of the patch you supply.
reviewdog alternatives
The documented scope is narrow and worth measuring alternatives against: reporters exist for GitHub, GitLab and Bitbucket, a local reporter is the default, and reviewdog only reposts findings that already exist in a parseable form. It does not run, configure, or replace the linter itself, so a tool that owns the whole lint pipeline overlaps with it only at the reporting step.
How do I install reviewdog in a GitHub Action?
The README points at the reviewdog/action-setup action, pinned in its example to commit d8edfce3dd5e1ec6978745e801f9c50b5ef80252 with the comment v1.4.0. Its reviewdog_version input is optional and the documented values are latest, nightly, or a specific v.X.Y.Z tag.
Official sources
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.
[](https://hysenlabs.com/projects/reviewdog-reviewdog)Star history chart for your README
[](https://hysenlabs.com/projects/reviewdog-reviewdog)Was this useful?