foundry/modules/golang-best-practices/SKILL.md
Use when writing production Go 1.24+ code: generics with constraints, structured concurrency via errgroup and context, comprehensive error handling with wrapped sentinels, and performance-profiled service design.
npx skillsauth add cubetiq/cubis-foundry golang-best-practicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Production-grade guidance for Go 1.24+ covering generics with practical constraints, structured concurrency using errgroup and context propagation, comprehensive error handling with sentinel values and wrapped chains, module design for libraries and services, and performance profiling discipline with pprof and benchmarks.
Accept interfaces, return structs — define small interfaces (1–3 methods) at the call site, not the implementation site, because Go interfaces are implicitly satisfied and defining them at the consumer avoids coupling to implementation details. Return concrete types so callers get full access without type assertion.
Pass context.Context as the first parameter everywhere — every function that touches the network, disk, or a database must accept ctx context.Context as its first argument. Never store a context in a struct field because contexts carry request-scoped deadlines and cancellation signals that become stale when the struct outlives the request.
Wrap errors with fmt.Errorf("operation: %w", err) — use %w to create error chains that errors.Is and errors.As can traverse. Define sentinel errors (var ErrNotFound = errors.New("not found")) for well-known failure modes. Create custom error types when the caller needs structured data (HTTP status, retry hint) because stringly-typed error matching breaks on rewording.
Use errgroup.Group for coordinated fan-out — replace manual sync.WaitGroup + channel error collection with errgroup.Group because it propagates the first error and cancels sibling goroutines via the derived context. Set concurrency limits with g.SetLimit(n) to prevent resource exhaustion.
Bound every goroutine's lifetime — never launch a goroutine without a cancellation path. Use select with ctx.Done() in loops and defer cancel() at the launch site. Leaked goroutines are the Go equivalent of memory leaks and they do not show up in standard tests; use goleak in CI to detect them.
Choose channels for ownership transfer, mutexes for shared state — channels excel when one goroutine produces a value and another consumes it. Use sync.Mutex or sync.RWMutex when multiple goroutines read/write the same struct field because channels for shared-state access create unnecessary complexity and deadlock risk.
Apply generics when the abstraction covers 3+ concrete types — write func Map[S any, T any](s []S, f func(S) T) []T when the function genuinely applies to multiple types. Avoid generics for 1–2 callers because the cognitive overhead exceeds the duplication cost. Limit type parameter lists to 2–3 parameters; if you need more, decompose.
Use iter.Seq and iter.Seq2 for lazy iteration (Go 1.23+) — implement range-over-function iterators for collections that should not allocate a full slice. This replaces callback-based iteration with a first-class language construct because range-func is composable and works with break/continue.
Test with table-driven subtests and race detection — structure tests as []struct{ name string; input X; want Y } with t.Run(tc.name, ...) for each case. Run go test -race -count=1 ./... in CI because the race detector catches data races that are invisible to functional tests. Use t.Parallel() where safe to speed up the suite.
Benchmark before optimizing — write func BenchmarkX(b *testing.B) with b.ReportAllocs() and b.ResetTimer() to isolate the hot path. Use go tool pprof (CPU, heap, goroutine, block, mutex profiles) for production profiling. Never optimize based on intuition because Go's escape analysis and GC behavior make allocation patterns non-obvious.
Structure modules with internal packages — use internal/ to hide implementation details from external consumers. Keep cmd/ for entry points, pkg/ only if the code is genuinely reusable outside the module, and domain packages at the root. Avoid util or common packages because they become dumping grounds with no cohesion.
Lint with golangci-lint and enforce in CI — enable govet, staticcheck, errcheck, gosec, revive, gocritic, and exhaustive at minimum. Use gofumpt for stricter formatting than gofmt. Treat lint failures as CI failures because linter findings in merged code are much more expensive to fix.
Build reproducible binaries — use go build -trimpath -ldflags='-s -w -X main.version=v1.2.3' for release builds. Keep go.mod tidy with go mod tidy. Use multi-stage Docker builds or ko for container images because they produce minimal images without a Go toolchain.
Instrument with OpenTelemetry — add tracing spans at service boundaries and structured logging with slog (Go 1.21+). Attach trace IDs, request IDs, and operation names to every log entry because correlated telemetry is the fastest path to diagnosing production incidents.
go test, table-driven cases, subtests, and helpers from the standard testing package for code-level checks.../web-testing/SKILL.md, ../android-emulator-testing/SKILL.md, or ../ios-simulator-testing/SKILL.md only when the task needs live browser or device evidence.Produces Go code following standard project layout with explicit error handling, context propagation, errgroup-based concurrency, and table-driven tests. Includes module structure guidance, benchmark setups, and inline comments explaining concurrency and error design choices.
| File | Load when |
| --- | --- |
| references/concurrency.md | Goroutine management, channels, errgroup, or context cancellation patterns needed. |
| references/error-handling.md | Error wrapping, sentinel errors, custom error types, or error middleware needed. |
| references/testing.md | Table-driven tests, race detection, benchmarks, or test fixtures needed. |
| references/module-design.md | Package layout, internal packages, dependency management, or API surface needed. |
| references/performance.md | Profiling, allocation analysis, escape analysis, or GC tuning needed. |
No helper scripts are required for this skill right now. Keep execution in SKILL.md and references/ unless repeated automation becomes necessary.
tools
Use when investigating latest vendor behavior, comparing tools or platforms, verifying claims beyond the repo, or gathering external evidence before implementation.
documentation
Use when designing database schemas, normalization strategies, indexing plans, query optimization, and migration workflows for relational, document, or hybrid data stores.
development
Use when writing, reviewing, or refactoring modern C#/.NET code, including minimal APIs, records, async streams, pattern matching, DI lifetimes, and memory-efficient performance tuning.
development
Use when conducting code reviews, building review checklists, calibrating review depth, providing structured feedback, or establishing team review practices. Covers review methodology, feedback patterns, automated checks, and batch review strategies.