# Go Best Practices

> This skill should be used when writing, reviewing, or discussing Go code — idioms, error handling, concurrency, and testing patterns.

- Skill: `lklimek/go-best-practices` (Agent Skill)
- Install (CLI): `npx skillmds@latest add lklimek/go-best-practices`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lklimek/go-best-practices/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: lklimek (https://skillmd.com/u/lklimek)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/lklimek/go-best-practices

---


# Go Best Practices

## Technical Standards
- **Go Version**: 1.21+ (or latest stable)
- **Code Style**: gofmt/goimports enforced
- **Linting**: golangci-lint with comprehensive checks
- **Testing**: go test with table-driven tests
- **Documentation**: One-line Godoc comment for every exported identifier; expand only when non-obvious
- **Error Handling**: Explicit with error wrapping (fmt.Errorf with %w)
- **Modules**: Go modules for dependency management
- **Context**: context.Context for cancellation and timeouts

## Best Practices
- Accept interfaces, return structs
- Keep interfaces small (single-method often best)
- Use context.Context for cancellation propagation
- Always check errors — don't ignore with `_`
- Use defer for cleanup (close files, unlock mutexes)
- Goroutines: always know when they exit
- Channels for communication, mutexes for state
- Prefer composition over embedding
- Use `internal/` package for private code
- Prefer standard library first

## Common Patterns
- **Error Wrapping**: `fmt.Errorf("context: %w", err)`
- **Options Pattern**: Functional options for constructors
- **Context**: Pass as first parameter
- **Interfaces**: io.Reader, io.Writer, io.Closer patterns
- **Middleware**: Handler wrapping for HTTP servers
- **Worker Pools**: Channel-based task distribution for bounded concurrency
- **Graceful Shutdown**: Signal handling with context cancellation

## Concurrency
- Use sync.WaitGroup to wait for goroutines
- Use buffered channels carefully — understand blocking
- Use select for channel multiplexing

## Error Handling
- Define custom error types for sentinel errors
- Use errors.Is() and errors.As() for checking
- Return errors as last return value
- Don't panic in library code — return errors
- Log errors at the right level in the call stack

## Code Quality Tools
- **Formatting**: gofmt, goimports
- **Linting**: golangci-lint (staticcheck, errcheck, govet, etc.)
- **Testing**: `go test -race -cover ./...`
- **Security**: gosec
- **Dependencies**: `go mod tidy`, `go mod verify`
- **Benchmarks**: `go test -bench=. -benchmem`

## Common Pitfalls
- Don't use global variables excessively
- Don't use init() unless absolutely necessary
- Don't over-use interfaces early — add when needed

## Code Review Checklist
- Idiomatic Go style (Effective Go compliance)
- Error handling: explicit checks, no ignored errors, proper wrapping with %w
- Goroutine lifecycle: clear start/stop, no leaks
- Interface design: small, focused, used appropriately
- Context propagation for cancellation
- Defer usage for cleanup
- DRY compliance: duplicated logic, copy-paste patterns
- Naming clarity: exported vs unexported, package naming
- Test quality: table-driven tests, meaningful assertions, race condition coverage
- Code brevity: flag code that can be expressed in fewer lines without losing clarity

Use `GO-NNN` prefix for all findings.

