---
title: New linters
---

## How to write a custom linter

Use `go/analysis` and take a look at [this tutorial](https://disaev.me/p/writing-useful-go-analysis-linter/): it shows how to write `go/analysis` linter
from scratch and integrate it into `golangci-lint`.

## How to add a public linter to `golangci-lint`

You need to implement a new linter using `go/analysis` API.
We don't accept not `go/analysis` linters.

After that:

1. Implement functional tests for the linter:
    - Add one file into directory [`test/testdata`](https://github.com/golangci/golangci-lint/tree/master/test/testdata).
    - Run `T=yourlintername.go make test_linters` to ensure that test fails.
    - Run `go run ./cmd/golangci-lint/ run --no-config --disable-all --enable=yourlintername ./test/testdata/yourlintername.go`
2. Add a new file `pkg/golinters/{yourlintername}.go`.
   Look at other linters in this directory.
   Implement linter integration and check that test passes.
3. Add the new struct for the linter (which you've implemented in `pkg/golinters/{yourlintername}.go`) to the
   list of all supported linters in [`pkg/lint/lintersdb/manager.go`](https://github.com/golangci/golangci-lint/blob/master/pkg/lint/lintersdb/manager.go)
   to the function `GetAllSupportedLinterConfigs`.
    - Add `WithSince("next_version")`, where `next_version` must be replaced by the next minor version. (ex: v1.2.0 if the current version is v1.1.0)
4. Find out what options do you need to configure for the linter.
   For example, `nakedret` has only 1 option: [`max-func-lines`](https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml).
   Choose default values to not being annoying for users of golangci-lint. Add configuration options to:
    - [.golangci.example.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml) - the example of a configuration file.
      You can also add them to [.golangci.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.yml)
      if you think that this project needs not default values.
    - [config struct](https://github.com/golangci/golangci-lint/blob/master/pkg/config/config.go) -
      don't forget about `mapstructure` tag for proper configuration files parsing by [pflag](https://github.com/spf13/pflag).
5. Take a look at the example of [Pull Request with new linter support](https://github.com/golangci/golangci-lint/pulls?q=is%3Apr+is%3Amerged+label%3A%22linter%3A+new%22).

## How to add a private linter to `golangci-lint`

Some people and organizations may choose to have custom-made linters run as a part of `golangci-lint`.
Typically, these linters can't be open-sourced or too specific.
Such linters can be added through Go's plugin library.

### Configure a Plugin

If you already have a linter plugin available, you can follow these steps to define it's usage in a projects
`.golangci.yml` file. An example linter can be found at [here](https://github.com/golangci/example-plugin-linter). If you're looking for
instructions on how to configure your own custom linter, they can be found further down.

1. If the project you want to lint does not have one already, copy the [.golangci.yml](https://github.com/golangci/golangci-lint/blob/master/.golangci.yml) to the root directory.
2. Adjust the yaml to appropriate `linters-settings:custom` entries as so:

```yaml
linters-settings:
  custom:
    example:
      path: /example.so
      description: The description of the linter
      original-url: github.com/golangci/example-linter
```

That is all the configuration that is required to run a custom linter in your project. Custom linters are enabled by default,
but abide by the same rules as other linters. If the disable all option is specified either on command line or in
`.golangci.yml` files `linters:disable-all: true`, custom linters will be disabled; they can be re-enabled by adding them
to the `linters:enable` list, or providing the enabled option on the command line, `golangci-lint run -Eexample`.

### Create a Plugin

Your linter must implement one or more `golang.org/x/tools/go/analysis.Analyzer` structs.
Your project should also use `go.mod`. All versions of libraries that overlap `golangci-lint` (including replaced
libraries) MUST be set to the same version as `golangci-lint`. You can see the versions by running `go version -m golangci-lint`.

You'll also need to create a go file like `plugin/example.go`. This MUST be in the package `main`, and define a
variable of name `AnalyzerPlugin`. The `AnalyzerPlugin` instance MUST implement the following interface:

```go
type AnalyzerPlugin interface {
    GetAnalyzers() []*analysis.Analyzer
}
```

The type of `AnalyzerPlugin` is not important, but is by convention `type analyzerPlugin struct {}`. See
[plugin/example.go](https://github.com/golangci/example-plugin-linter/blob/master/plugin/example.go) for more info.

To build the plugin, from the root project directory, run `go build -buildmode=plugin plugin/example.go`. This will create a plugin `*.so`
file that can be copied into your project or another well known location for usage in golangci-lint.
