golang
Use when writing, reviewing, or refactoring Go code. Provides production best practices for Go covering error handling, concurrency, naming, testing, performance, generics, iterators, and common pitfalls. Distilled from Google Go Style Guide, Uber Go Style Guide, Effective Go, and Go Code Review Com
By saisudhir14 · 512 installs
npx skills add saisudhir14/claude-skills --skill golang
Source repository · Upstream listing
Go Best Practices
Production patterns from Google, Uber, and the Go team. Updated for Go 1.25.
Sub skills: skills/go error handling , skills/go concurrency , skills/go testing , skills/go performance , skills/go code review , skills/go linting , skills/go project layout , skills/go security . Deep dive references in references/ .
Core Principles
Readable code prioritizes these attributes in order:
1. Clarity : purpose and rationale are obvious to the reader
2. Simplicity : accomplishes the goal in the simplest way
3. Concision : high signal to noise ratio
4. Maintainability : easy to modify correctly
5. Consistency : matches surrounding codebase
Error Handling
Full guide: skills/go error handling/SKILL.md Reference: references/error handling.md
Return errors, never panic in production code
Wrap with %w when callers need errors.Is / errors.As ; use %v at boundaries
Keep context succinct : "new store: %w" not "failed to create new store: %w"
Handle errors once : don't log and return the same error
Error strings : lowercase, no punctuation
Indent error flow : handle errors first, keep happy path at minimal indentation
Use errors.Join (Go 1.20+) for multiple independent failures
Sentinel errors : Err prefix for vars, Error suffix for types
Concurrency
Full guide: skills/go concurrency/SKILL.md Reference: references/concurrency.md
Channel size : 0 (unbuffered) or 1; anything else needs justification
Document goroutine lifetimes : when and how they exit
Use errgroup.Group over manual sync.WaitGroup for error returning goroutines
Prefer synchronous functions : let callers add concurrency
Zero value mutexes : don't use pointers; don't embed in public structs
Typed atomics (Go 1.19+): atomic.Int64 , atomic.Bool , atomic.Pointer[T]
sync.Map (Go 1.24+): significantly improved performance for disjoint key sets
Naming
MixedCaps always : never underscores ( MaxLength not MAX LENGTH )
Initialisms : consistent case ( URL , ID , HTTP not Url , Id , Http )
Short variables : scope determines length ( i for loops, DefaultTimeout for globals)
Receiver names : 1 2 letter abbreviation, consistent across methods, never this / self
Package names : lowercase single word, no util / common / misc
No repetition : http.Serve not http.HTTPServe ; c.WriteTo not c.WriteConfigTo
Pointer vs Value Receivers
Pointer receiver Value receiver
Modifies receiver Small, immutable struct
Large struct Doesn't modify state
Contains sync.Mutex Map, func, or chan
Consistency with other methods Basic types
Imports
Three groups: stdlib, external, internal (separated by blank lines)
Rename only to avoid collisions
No dot imports except test files with circular deps
Blank imports ( import "pkg" ) only in main or tests
Module Management (Go 1.24+)
Track tool dependencies in go.mod with tool directives:
Structs
Always use field names in initialization (positional breaks on changes)
Omit zero value fields
Don't embed types in public structs (exposes API unintentionally)
Use var for zero value structs : var user User
Slices and Maps
Nil slices preferred : var t []string (use []string{} only for JSON [] encoding)
Copy at boundaries : copy() or maps.Clone() to prevent mutation
Preallocate : make([]T, 0, len(input)) when size is known
Use slices and maps packages : slices.Sort , slices.Clone , maps.Clone , maps.Equal
Generics (Go 1.18+)
Use when writing identical code for different types
Use cmp.Ordered or custom constraints for type safety
Generic type aliases (Go 1.24+): type Set[T comparable] = map[T]struct{}
Don't over generalize : use concrete types or interfaces when they suffice
Iterators (Go 1.23+)
Range over functions for custom iterators:
String/bytes iterators (Go 1.24+): strings.Lines , strings.SplitSeq , strings.SplitAfterSeq
Structured Logging (Go 1.21+)
slog.DiscardHandler (Go 1.24+) for suppressing logs in tests
Use consistent key names, group related fields with slog.Group
Performance
Full guide: skills/go performance/SKILL.md Reference: references/performance.md
strconv over fmt : strconv.Itoa(n) not fmt.Sprintf("%d", n)
Avoid repeated []byte conversions : store once, reuse
Preallocate map capacity : make(map[string]int, len(items))
strings.Builder with Grow() for concatenation
Testing
Full guide: skills/go testing/SKILL.md Reference: references/testing.md
Table driven tests with t.Parallel() for subtests
go cmp over reflect.DeepEqual for clear diff output
Useful failure messages : include input, got, want
t.Fatal for setup failures
Interfaces belong to consumers , not producers
T.Context and T.Chdir (Go 1.24+)
b.Loop() (Go 1.24+): cleaner benchmarks, no b.ResetTimer() needed
synctest.Test (Go 1.25+): deterministic concurrent testing with synthetic time
Resource Management (Go 1.24+)
runtime.AddCleanup : multiple cleanups per object, no cycle leaks (replaces SetFinalizer )
weak.Pointer[T] : weak references for caches, canonicalization, observers
os.Root : scoped file access preventing path traversal attacks
Patterns
Full reference: references/patterns.md
Functional options : WithTimeout(d) , WithLogger(l) for configurable constructors
Interface compliance : var http.Handler = ( Handler)(nil)
Defer for cleanup : small overhead, worth the safety
Graceful shutdown : signal handling + srv.Shutdown(ctx)
Enums start at one : zero = invalid/unset
Use time.Duration : never raw ints for time
Two value type assertions : t, ok := i.(string) to avoid panics
Context first : func Process(ctx context.Context, ...)
Avoid mutable globals : use dependency injection
Avoid init() : prefer explicit initialization in main
//go:embed (Go 1.16+): embed static files
Field tags : explicit json:"name" on marshaled structs
Container aware GOMAXPROCS (Go 1.25+): automatic cgroup based tuning
Common Gotchas
Full reference: references/gotchas.md
Gotcha Fix
Loop variable capture (pre 1.22) Fixed in Go 1.22+ (per iteration vars)
Defer evaluates args immediately Capture in closure
Nil interface vs nil pointer Return nil explicitly
Use result before error check Always check err first (Go 1.25 enforces)
Map iteration order Sort keys with slices.Sorted(maps.Keys(m))
Slice append shared backing Full slice expression a[:2:2]
Linting
Full guide: skills/go linting/SKILL.md
Use golangci lint as the standard linter aggregator
Recommended linters : errcheck, govet, staticcheck, revive, gosimple, goimports, errorlint, bodyclose
Add as a tool dependency (Go 1.24+): go get tool github.com/golangci/golangci lint/cmd/golangci lint
Run in CI : use golangci/golangci lint action for GitHub Actions
Suppress sparingly : prefer fixing over //nolint comments
Project Layout
Full guide: skills/go project layout/SKILL.md
cmd/ : one subdirectory per executable, keep main.go thin
internal/ : private packages, enforced by the Go toolchain
Avoid pkg/ , src/ , models/ , utils/ : name packages by purpose
Flat is fine : small projects should not have deep directory trees
Dockerfile : multi stage build, CGO ENABLED=0 , distroless base image
Security
Full guide: skills/go security/SKILL.md
Parameterized SQL queries : never interpolate user input
os.Root (Go 1.24+): scoped file access preventing path traversal
Validate at boundaries : decode into typed structs, validate fields
Never hardcode or log secrets : use Secret type with redacted String()
Standard crypto only : crypto/rand for random bytes, bcrypt for passwords
HTTP timeouts : always set ReadTimeout , WriteTimeout , IdleTimeout
govulncheck : scan dependencies for known vulnerabilities
go test race : always run with the race detector in CI
Experimental (Go 1.25)
encoding/json/v2 : enable with GOEXPERIMENT=jsonv2 . Better performance, streaming, custom marshalers per call.
Documentation
Comments are full sentences starting with the declared name
Package comments: before package declaration, no blank line
References
1. [Google Go Style Guide](https://google.github.io/styleguide/go/)
2. [Uber Go Style Guide](https://github.com/uber go/guide)
3. [Effective Go](https://go.dev/doc/effective go)
4. [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments)
5. [Go 1.23 Release Notes](https://go.dev/doc/go1.23)
6. [Go 1.24 Release Notes](https://go.dev/doc/go1.24)
7. [Go 1.25 Release Notes](https://go.dev/doc/go1.25)