golangci-lint: The Guide to Go Code Quality

In the world of Go development, code quality isn’t just about making your code work—it’s about making it maintainable, efficient, and bug-free. Enter golangci-lint, the Swiss Army knife of Go linters that has become the industry standard for ensuring code quality across Go projects.

Unlike running individual linters separately, golangci-lint aggregates dozens of linters into a single, blazingly fast tool. It runs linters in parallel, caches results, and provides a unified configuration system. Whether you’re working on a small microservice or a large-scale distributed system, golangci-lint is an essential tool in your development workflow.

Why golangci-lint Matters

Before golangci-lint, Go developers had to run multiple linting tools separately: go vet, errcheck, staticcheck, gosimple, and many others. This approach had several problems:

  • Slow execution: Running linters sequentially wasted valuable development time
  • Inconsistent configuration: Each linter had its own configuration format
  • CI/CD complexity: Setting up multiple tools in pipelines was tedious
  • Missed issues: Forgetting to run a particular linter meant missing potential bugs

golangci-lint solves all these problems by providing a unified interface to 50+ linters, running them in parallel, and offering intelligent caching that can speed up subsequent runs by 5x or more.

Installation

Getting started with golangci-lint is straightforward. Choose the method that works best for your environment:

Using Go Install (Recommended)

go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

Using Homebrew (macOS/Linux)

brew install golangci-lint

Basic Usage

The simplest way to use golangci-lint is to run it in your project directory:

golangci-lint run

This command will:

  1. Discover all Go files in your project
  2. Run a set of default enabled linters
  3. Report any issues found

Targeting Specific Paths

You can lint specific packages or files:

# Lint everything recursively
golangci-lint run ./...

# Lint a specific package
golangci-lint run ./pkg/api

# Lint specific files
golangci-lint run main.go handler.go

Viewing Available Linters

To see all available linters and their status:

golangci-lint linters

This command shows which linters are enabled by default and provides brief descriptions of what each linter does.

Configuration: The .golangci.yml File

The real power of golangci-lint comes from its configuration system. Create a .golangci.yml file in your project root to customize behavior:

# .golangci.yml
run:
  # Timeout for analysis
  timeout: 5m
  
  # Include test files
  tests: true
  
  # Modules download mode
  modules-download-mode: readonly

linters:
  # Enable specific linters
  enable:
    - errcheck
    - gosimple
    - govet
    - ineffassign
    - staticcheck
    - unused
    - misspell
    - gocyclo
    - dupl
    - gocritic
    
  # Disable problematic linters
  disable:
    - typecheck  # Can conflict with generated code

# Configure individual linters
linters-settings:
  errcheck:
    # Check type assertions
    check-type-assertions: true
    # Check blank assignments
    check-blank: true
    
  gocyclo:
    # Maximum cyclomatic complexity
    min-complexity: 15
    
  dupl:
    # Minimum token sequence for duplication
    threshold: 100
    
  govet:
    # Enable shadow checking
    check-shadowing: true

# Issue filtering
issues:
  # Maximum issues to report (0 = unlimited)
  max-issues-per-linter: 0
  max-same-issues: 0
  
  # Exclude specific rules
  exclude-rules:
    # Exclude some linters from running on tests
    - path: _test\.go
      linters:
        - errcheck
        - dupl
        - gosec

Conclusion

golangci-lint is an indispensable tool for Go developers who care about code quality. By aggregating dozens of linters into a single, fast tool with a unified configuration, it makes maintaining high code standards effortless.

Start simple with the default configuration, then gradually enable more linters as your team becomes comfortable with the tool. Integrate it into your editor, pre-commit hooks, and CI/CD pipeline to catch issues early.

Remember that linters are tools to help you write better code—not rigid rules to be followed blindly. Use your judgment to configure golangci-lint appropriately for your project’s needs, and don’t hesitate to exclude false positives or disable linters that don’t add value to your specific context.

The time invested in properly configuring golangci-lint will pay dividends in fewer bugs, more maintainable code, and a smoother development experience for your entire team.

Additional Resources