go-code-review
Use when reviewing Go code or checking code against community style standards. Also use proactively before submitting a Go PR or…
Use when optimizing Go code, investigating slow performance, or writing performance-critical sections. Also use when a user mentions slow Go code, string concatenation in loops, or asks about benchmarking, even if the user doesn't explicitly mention performance patterns. Does
$ npx -y skills add cxuu/golang-skills --skill go-performance --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/go-performanceContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when optimizing Go code, investigating slow performance, or writing performance-critical sections. Also use when a user mentions slow Go code, string concatenation in loops, or asks about benchmarking, even if the user doesn't explicitly mention performance patterns. Does
name: go-performance description: Use when optimizing Go code, investigating slow performance, or writing performance-critical sections. Also use when a user mentions slow Go code, string concatenation in loops, or asks about benchmarking, even if the user doesn't explicitly mention performance patterns. Does not cover concurrent performance patterns (see go-concurrency). allowed-tools: Bash(bash:*)
Performance-specific guidelines apply only to the **hot path**. Don't prematurely optimize—focus these patterns where they matter most.
---
When converting primitives to/from strings, `strconv` is faster than `fmt`:
s := strconv.Itoa(rand.Int()) // ~2x faster than fmt.Sprint()
| Approach | Speed | Allocations | |----------|-------|-------------| | `fmt.Sprint` | 143 ns/op | 2 allocs/op | | `strconv.Itoa` | 64.2 ns/op | 1 allocs/op |
---
Convert a fixed string to `[]byte` once outside the loop:
data := []byte("Hello world")
for b.Loop() { // Go 1.24+; use b.N loops only for older Go
w.Write(data) // ~7x faster than []byte("...") each iteration
}---
Specify container capacity where possible to allocate memory up front. This minimizes subsequent allocations from copying and resizing as elements are added.
Provide capacity hints when initializing maps with `make()`:
m := make(map[string]os.DirEntry, len(files))
**Note**: Unlike slices, map capacity hints do not guarantee complete preemptive allocation—they approximate the number of hashmap buckets required.
Provide capacity hints when initializing slices with `make()`, particularly when appending:
data := make([]int, 0, size)
Unlike maps, slice capacity is **not a hint**—the compiler allocates exactly that much memory. Subsequent `append()` operations incur zero allocations until capacity is reached.
| Approach | Time (100M iterations) | |----------|------------------------| | No capacity | 2.48s | | With capacity | 0.21s |
The capacity version is **~12x faster** due to zero reallocations during append.
---
Don't pass pointers as function arguments just to save a few bytes. If a function refers to its argument `x` only as `*x` throughout, then the argument shouldn't be a pointer.
func process(s string) { // not *string — strings are small fixed-size headers
fmt.Println(s)
}**Common pass-by-value types**: `string`, `io.Reader`, small structs.
**Exceptions**:
---
Choose the right strategy based on complexity:
| Method | Best For | |--------|----------| | `+` | Few strings, simple concat | | `fmt.Sprintf` | Formatted output with mixed types | | `strings.Builder` | Loop/piecemeal construction | | `strings.Join` | Joining a slice | | Backtick literal | Constant multi-line text |
---
Always measure before and after optimizing. Use Go's built-in benchmark framework and profiling tools.
go test -bench=. -benchmem -count=10 ./...
> **Validation**: After applying optimizations, run `bash scripts/bench-compare.sh` to measure the actual impact. Only keep optimizations with measurable improvement.
---
| Pattern | Bad | Good | Improvement | |---------|-----|------|-------------| | Int to string | `fmt.Sprint(n)` | `strconv.Itoa(n)` | ~2x faster | | Repeated `[]byte` | `[]byte("str")` in loop | Convert once outside | ~7x faster | | Map initialization | `make(map[K]V)` | `make(map[K]V, size)` | Fewer allocs | | Slice initialization | `make([]T, 0)` | `make([]T, 0, cap)` | ~12x faster | | Small fixed-size args | `*string`, `*io.Reader` | `string`, `io.Reader` | No indirection | | Simple string join | `s1 + " " + s2` | (already good) | Use `+` for few strings | | Loop string build | Repeated `+=` | `strings.Builder` | O(n) vs O(n²) |
---
AI Agent Skills for writing idiomatic, production-quality Go code. 20 modular skills teach AI coding assistants Go best practices derived from: Google Go Style Guide Effective Go Uber Go Style Guide Go Wiki CodeReviewComments Skills are tuned following
Use when reviewing Go code or checking code against community style standards. Also use proactively before submitting a Go PR or…
Use when writing concurrent Go code — goroutines, channels, mutexes, or thread-safety guarantees. Also use when parallelizing…
Use when working with context.Context in Go — placement in signatures, propagating cancellation and deadlines, and storing values…
Use when writing conditionals, loops, or switch statements in Go — including if with initialization, early returns, for loop…
Use when working with Go slices, maps, or arrays — choosing between new and make, using append, declaring empty slices (nil vs…
Use when declaring or initializing Go variables, constants, structs, or maps — including var vs :=, reducing scope with if-init,…