CLI tool
reviewdog/reviewdog avatar
reviewdog/reviewdog

reviewdog: lint output as review comments on GitHub, GitLab and Bitbucket

Automated code review tool integrated with any code analysis tools regardless of programming language.

9,623 stars499 forksGoMIT

At a glance

What is it?
reviewdog turns any linter's stdout into inline review comments, filtered to the lines a pull request actually touched. It is a diff filter and a comment poster, not a linter, and the errorformat string is where most first attempts fail.
Who is it for?
Adopt reviewdog if you already run linters in CI and want their findings attached to the lines a pull request changed, on GitHub, GitLab or Bitbucket, without teaching each linter a new output format. Skip it if you need a whole-repository quality gate, a hosted dashboard, or a tool that can classify findings semantically rather than parse them from text.
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 last received commits 4 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 September 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap reviewdog fills between a linter and a pull request

A linter run in CI prints a wall of text into a log nobody opens. A linter wired into a code review bot usually means writing an adapter per tool, per hosting service, and then deciding which of the thousands of pre-existing findings deserve a comment on a twenty-line pull request. reviewdog takes a narrower position. It accepts linter output on stdin, parses it with a Vim-style errorformat pattern, keeps only the findings that fall inside the diff under review, and posts those as comments through a reporter.

The intended user is a team that already has linters and already reviews pull requests, and wants the two connected without changing either. The README states the goal plainly: it provides a way to post review comments to code hosting services automatically by integrating with any linter tool. The word any is doing real work here. reviewdog does not know what golint, ESLint or RuboCop are. It knows line-oriented text and diffs.

That also defines who it is not for. If you want a service that reads a diff and reasons about it, reviewdog has no model and makes no judgement. It is plumbing between two things you already own.

How the errorformat parser and the diff filter work together

The pipeline has four visible stages, and the repository layout reflects them. A parser package reads stdin, a diff package computes which lines changed, a filter package intersects the two, and a service package talks to the hosting provider.

The parser is the part that surprises people. reviewdog uses errorformat, described in the README as a port of Vim's errorformat feature, supplied through the -efm flag. Each placeholder maps to a field: %f is a file name, %l a line number, %c a column number, %m the message, and %% matches a literal percent sign. If a tool prints comment_iowriter.go:11:6: exported type CommentWriter should have comment or be unexported, then %f:%l:%c: %m is the pattern that describes it. The README points readers to the reviewdog/errorformat repository for more complex cases, which is a signal that real linter output often needs more than one pattern.

Alongside errorformat, reviewdog accepts other input shapes. The README lists a Reviewdog Diagnostic Format (RDFormat), checkstyle format, and SARIF format, and the go.mod file shows a dependency on github.com/haya14busa/go-sarif. Those alternatives matter because errorformat is a line pattern language, and tools that emit structured JSON or XML are better served by a format that carries structure.

Once parsed, findings are compared against a diff, which the README shows being supplied with -diff="git diff FETCH_HEAD". A finding outside the changed lines does not become a comment. That single rule is what keeps a legacy codebase from drowning in annotations on the first run.

Installing reviewdog and posting your first diff comment

The README's installation section leads with a shell installer that fetches a release binary. It installs into ./bin/ by default, and the same script accepts a -b flag for the destination directory and an optional version argument.

bash
curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/fd59714416d6d9a1c0692d872e38e7f8448df4fc/install.sh | sh -s

Running that should leave a reviewdog executable in ./bin/. If you prefer a package manager, the README documents brew install reviewdog/tap/reviewdog and, on Windows, scoop install reviewdog. There is also a Go path, go install github.com/reviewdog/reviewdog/cmd/reviewdog@latest, which requires the Go toolchain version declared in go.mod.

The quickest real use is local, with no hosting service involved. The default reporter is local, so reviewdog prints filtered findings to the terminal. The README's own example pipes golint into reviewdog with an errorformat and a diff:

bash
golint ./... | reviewdog -efm="%f:%l:%c: %m" -diff="git diff FETCH_HEAD"

What you should see is only those golint findings that land on lines your diff touched. If the output is empty while golint alone is noisy, the errorformat is the first thing to check, not the diff.

For CI, the README documents a GitHub Action, reviewdog/action-setup, which installs the binary and takes a reviewdog_version input whose documented values are latest, nightly, or a vX.Y.Z tag. Once the binary is on the path, the same pipeline runs inside the workflow, with a reporter other than local.

yaml
steps:
- uses: reviewdog/action-setup@d8edfce3dd5e1ec6978745e801f9c50b5ef80252 # v1.4.0
  with:
    reviewdog_version: latest # Optional. [latest,nightly,v.X.Y.Z]

There is also a nightly install script pointed at the reviewdog/nightly repository for readers who want the newest build each day. That is a separate distribution channel, not the stable release.

Choosing a reporter across GitHub, GitLab and Bitbucket

The reporter decides where a finding ends up, and the README documents a long list of them. On GitHub the options are github-pr-check, github-check, github-pr-review, github-annotations and github-pr-annotations. GitLab has gitlab-mr-discussion and gitlab-mr-commit. Bitbucket gets bitbucket-code-report, built on the bitbucket-insights-api dependency visible in go.mod.

These are not interchangeable, and the names hint at the difference. A check reporter creates a status or check run with annotations attached. A review comment reporter creates a conversation thread on the pull request, which is what most teams picture when they say inline comment. An annotation reporter writes to the file view rather than the conversation. On GitLab, the discussion reporter opens merge request discussions while the commit reporter attaches to the commit.

The practical constraint is permissions. A reporter that opens review comments needs a token allowed to write comments; a reporter that only sets a check status needs less. The README does not spell out a permission matrix per reporter, so the safe sequence is to start with -reporter=local, confirm the filtering is right, then move to the least privileged hosted reporter that satisfies the team, and only then to review comments. Teams that jump straight to the comment reporter on a busy repository often discover that a misconfigured errorformat produces a comment per line.

Where reviewdog stops being the right tool

The diff filter is the feature and the limitation. reviewdog comments on changed lines. It does not track whether a finding was fixed, does not assign ownership, does not store history, and does not produce a repository-wide quality score. If your goal is a dashboard that trends lint debt over quarters, reviewdog is the wrong layer; it is a per-pull-request commenter.

The second limitation is the parser. errorformat is a pattern language for line-oriented text. A linter that prints multi-line findings, wraps messages, or interleaves progress output will not parse cleanly with a single -efm. The README's pointer to the errorformat repository for complex output is an acknowledgement of this, not a workaround. The structured alternatives (RDFormat, checkstyle, SARIF) exist precisely because text patterns are brittle, and adopting one of them usually means running the linter through a formatter first.

The third is the fail behaviour. reviewdog has exit codes and a fail level, and the README devotes a section to exit codes and a section to filter mode. The distinction between "post a comment" and "fail the build" is a configuration decision, and getting it wrong produces one of two bad outcomes: a red build for a cosmetic finding, or a green build while comments pile up unread. Neither is a defect in reviewdog, but both are common first-week mistakes.

Finally, reviewdog is a Go project that shells out to linters. The linter binaries must exist in the CI image. reviewdog does not install ESLint or RuboCop for you, and the reviewdog/action-eslint and reviewdog/action-rubocop style actions in the ecosystem exist to combine the two steps.

reviewdog compared with Danger

The comparison people search for is reviewdog versus Danger, and the difference is in where the logic lives. Danger is a general-purpose rule engine for pull requests. You write Ruby or JavaScript that inspects the pull request and decides what to say; the rules can be about anything, from changelog presence to commit message format. It does not parse linter output for you.

reviewdog inverts that. It ships the parsing and the diff intersection, and gives you nothing to program. You supply an errorformat and a linter command. That means less code and a narrower scope: reviewdog cannot enforce "every pull request must update the changelog" unless a linter prints that as a finding with a file and line.

The two are not mutually exclusive. A repository can use Danger for policy and reviewdog for lint findings, because they attach to the same pull request through different mechanisms. The choice is really about whether your rules are text-matching rules or code rules. Text-matching rules belong in reviewdog; anything that needs to read the pull request body, labels or commit graph belongs in Danger.

A second alternative worth naming is the linter's own native integration. Many linters now ship a GitHub Action that annotates a diff directly. If you use exactly one linter and it has a maintained action, that action may be less setup than reviewdog. reviewdog earns its place when you have several linters across several languages and want one configuration shape for all of them.

Maintenance, licensing and the cost of the pinned install script

The repository is not archived. The most recent release listed is v0.21.0, dated 2025-09-03, and the last push to the default branch was on 2025-09-03. The release before it, v0.20.3, is dated 2024-12-04. The cadence is therefore irregular rather than continuous, and anyone adopting reviewdog should plan around that rather than assume frequent releases.

The practical upgrade cost is low for the binary itself, because reviewdog delegates linting to external tools and its own interface is a command line with flags. Upgrading means replacing one binary. The cost sits in two places: the pinned install script URL, which in the README points at a specific commit hash rather than a branch, and the errorformat dependency, which is itself a separate module (github.com/reviewdog/errorformat) with its own version in go.mod. If you build from source, both move together.

The licence is MIT, per the LICENSE file at the repository root. That permits use, modification and redistribution with the licence and copyright notice retained. It says nothing about the licences of the linters you pipe into reviewdog, or the terms of the hosting service you post comments to, and those are separate questions. Nothing here is legal advice; check the MIT text itself and your organisation's policy.

One operational note the README does not address: rollback. There is no documented procedure for removing comments that reviewdog already posted. If a misconfigured errorformat floods a pull request, cleanup is manual.

Editorial conclusion

Adopt reviewdog if you already run linters in CI and want their findings attached to the lines a pull request changed, on GitHub, GitLab or Bitbucket, without teaching each linter a new output format. Skip it if you need a whole-repository quality gate, a hosted dashboard, or a tool that can classify findings semantically rather than parse them from text. Before rolling it out on a shared repository, verify three things in a scratch pull request: that your -efm pattern matches your linter's real output, which -reporter you have permission to use, and what -fail-on-error does to your job status when findings appear outside the diff.

Frequently asked questions

How does reviewdog compare with Danger?

Danger is a rule engine where you write code to inspect a pull request and decide what to say. reviewdog instead parses linter output with an errorformat pattern and posts only the findings inside the diff, so it covers text-matching rules but not policy checks that need the pull request body, labels or commit graph.

What are the alternatives to reviewdog?

The README positions reviewdog as a bridge between any linter and a hosting service, and the two realistic alternatives are Danger for programmable pull request rules and a linter's own native CI integration. The latter can be less setup if you use exactly one linter and it ships a maintained action; reviewdog pays off when several linters across languages need one configuration shape.

Do you get paid on GitHub?

reviewdog's README and repository files do not discuss GitHub payment or sponsorship. They cover hosting integrations such as the GitHub reporters github-pr-review and github-check, and the reviewdog/action-setup action that installs the binary in a workflow.

Why do people use Gerrit?

reviewdog's documentation does not discuss Gerrit. Its documented hosting integrations are GitHub, GitLab and Bitbucket, through reporters such as github-pr-review, gitlab-mr-discussion and bitbucket-code-report.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
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/reviewdog-reviewdog.svg)](https://hysenlabs.com/projects/reviewdog-reviewdog)