| name | lang-go |
| description | Go coding best practices and patterns. Use when working with Go or Golang files: implementation, testing, refactoring, architectural review, goroutines, channels, interfaces, error handling, memory management, and API development. |
10x Go
This skill defines rules to write robust, maintainable, and idiomatic production Go code.
Reference Guide
Load the relevant reference when the task involves:
| Topic | File | Load When |
|---|
| Concurrency | references/concurrency.md | goroutines, channels, context, sync primitives, worker pools |
| Generics | references/generics.md | type parameters, constraints, generic data structures |
| Interface Design | references/interfaces.md | interface composition, functional options, io patterns, DI |
| Testing | references/testing.md | tests, benchmarks, fuzzing, mocking, coverage |
| Project Structure | references/project-structure.md | module layout, go.mod, Makefile, Dockerfile, monorepo |
| Error Handling | references/errors.md | sentinel errors, wrapping, custom types, GORM context |
| API Projects | references/api.md | gin, GORM, JWT, swagger, CORS |
| OpenAPI / Swagger | references/openapi.md | swaggo annotations, spec generation, Swagger UI, security schemes |
| CLI Projects | references/cli.md | cobra, CLI directory layout |
| REST Patterns | references/rest-patterns.md | URI patterns, HTTP status code, naming conventions |
| Memory & Resources | references/memory.md | request/response body lifecycle, goroutine limits, heap escape, sync.Pool |
Architecture Principles
- Favor simplicity. Do not over-engineer the design.
- Depend on interfaces, not concrete types (DI). Prefer small, single-method interfaces (ISP). Each function/type has one responsibility (SRP).
- Favor generic functions over specific ones (
hasRole(string) instead of hasAdminRole() and hasWriterRole()).
- ALWAYS make small, atomic, incremental changes rather than big-bang rewrites.
- Introduce interfaces when needed to enable loose coupling.
MUST DO
- Run
gofmt and golangci-lint on all generated code
- Run
go vet ./... on all generated code (catches common correctness issues gofmt misses)
- Pass
context.Context as the first argument to all blocking or I/O-bound functions
- Handle all errors explicitly — no naked
_ discards without justification
- Wrap errors with
fmt.Errorf("operationName: %w", err) — see references/errors.md
- Write table-driven tests with
t.Run subtests for all non-trivial functions
- Document all exported functions, types, and constants with a docstring
- Run tests with
-race flag: go test -race ./...
- Always apply
http.MaxBytesReader, drain, and close r.Body in HTTP handlers
- Always limit, drain, and close
resp.Body in HTTP clients — use io.LimitedReader{R: resp.Body, N: limit+1} and check limited.N == 0 to detect (and error on) overflow; never use bare io.ReadAll(resp.Body)
- Always close
resp.Body on client.Do() error: if resp != nil { resp.Body.Close() } before returning
- Compile regular expressions once at package level (
var re = regexp.MustCompile(...)) — never inside functions called per request
- Cap goroutine counts with
errgroup.SetLimit or semaphore.NewWeighted — never spawn unbounded goroutines over user-supplied input
- Pre-allocate slices and maps when final size is known:
make([]T, 0, n)
- Use
errors.Is() and errors.As() for error inspection
- Use
any instead of interface{}
- Use type switches instead of repeated type assertions
MUST NOT DO
- Use
panic for recoverable errors
- Use
http.Get, http.Post, or http.DefaultClient in production code — always create a dedicated *http.Client with an explicit Timeout
- Use
io.LimitReader when you need truncation detection — use io.LimitedReader{N: limit+1} and check N==0 instead; io.LimitReader silently truncates
- Create goroutines without a clear termination strategy (WaitGroup, errgroup, or channel signaling)
- Ignore context cancellation in long-running operations
- Hardcode configuration values — use environment variables or functional options
- Use reflection without measurable performance justification
- Return errors without wrapping context (
return err alone loses the call site)
- Log AND return the same error at the same level — choose one
- Box value types into
any/interface{} on hot paths without profiling justification
- Use
fmt.Sprintf for string building in loops — use strings.Builder instead
- Store pointers to pooled objects outside the
sync.Pool scope
Coding Style
- Use PascalCase for exported types/methods, camelCase for variables
- Group imports: standard library, then third-party, then project-specific
- Package names and all exported entities must have docstrings
- Code must be self-documenting with clear, consistent naming
- Avoid nested logic — follow the "happy path" principle
Quality Standards
- Minimum Go version: 1.22+
- Functions must be small, focused, and easily testable.
- Dependencies must be minimal and well-justified.
- Performance optimizations must be measured, not assumed. Profile with pprof before optimizing.
- Log at Debug level by default; log at Info level for one-time or important events (initialization, configuration).
- Never log secrets, tokens, or PII — scrub before logging.
- Use parameterized GORM queries; never concatenate user input into raw SQL.
- Run
govulncheck ./... in CI to detect known vulnerabilities in dependencies.
Module Preferences
go.uber.org/zap for structured logging
github.com/stretchr/testify and its submodules (require, assert, suite) for testing
Tests
Tests are contracts with the user. See references/testing.md for full guidance. Key rules are in MUST DO above.
Agent Behavior
- Reduce redundancy — use tree-sitter (if available) to identify similar code patterns before generating new code.
- Use tree-sitter (if available) to analyze function complexity before refactoring.
- Preserve test intent: you may refactor test structure and helpers freely, but you MUST ASK for confirmation before changing test assertions, removing test cases, or altering expected behavior.
- When adding new test cases: add with a
// TODO: uncomment and validate comment and notify the user.