Help us improve
Share bugs, ideas, or general feedback.
From google-go-style
Use when writing, reviewing, or refactoring Go code; when handling errors (fmt.Errorf, %w, sentinel, errors.Is, errors.As); when deciding between panic, error return, and log.Fatal; when writing tests (table-driven, t.Helper, t.Fatal vs t.Error, goroutines); when designing API surface (option struct, variadic options, channel direction, context); when naming functions, methods, packages, receivers, or test doubles; when laying out packages and imports; when initializing variables or building strings.
npx claudepluginhub cicdteam/google-go-style --plugin google-go-styleHow this skill is triggered — by the user, by Claude, or both
Slash command
/google-go-style:google-go-styleThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
_Derived from the [Google Go Style Guide](https://google.github.io/styleguide/go/), © Google LLC, licensed [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/). This skill is a derivative digest, not a verbatim reproduction._
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Migrates code, prompts, and API calls from Claude Sonnet 4.0/4.5 or Opus 4.1 to Opus 4.5, updating model strings on Anthropic, AWS, GCP, Azure platforms.
Breaks plans, specs, or PRDs into thin vertical-slice issues on the project issue tracker using tracer bullets. Useful for converting high-level work into grabbable implementation tickets.
Share bugs, ideas, or general feedback.
Derived from the Google Go Style Guide, © Google LLC, licensed CC-BY 3.0. This skill is a derivative digest, not a verbatim reproduction.
Codifies the Google Go Style Guide (canonical + normative + best-practices) into actionable rules.
The full guide is large. This file holds only what should be in your head on every Go change. For deeper rules, load the matching references/*.md. For unusual situations, WebFetch the source — the guide is normative.
Apply on every line of Go you write or review.
Get prefix on getters. User(), not GetUser(). Exception: the underlying concept is "get" (HTTP GET).bytes.Buffer, not bytes.BytesBuffer. widget.New, not widget.NewWidget.this, self, me, or _ (unless unused). func (c *Config), not func (config *Config).URL, ID, HTTP, DB. Exported: UserID, ServeHTTP. Unexported: userID, urlPath. Never Url, Id, Http.Stub / Fake / Spy / Mock (or describe behaviour: AlwaysCharges, AlwaysDeclines).util / common / helper / model package names. They invite import renames at every call site. Name by what the package provides.*_test.go test/benchmark/example names, and packages imported only by generated code).i, c, db for tight loops; userCount, pollInterval for file scope. Don't drop letters to save typing (Sandbox, not Sbx).fmt.Errorf("doing X: %w", err) — wrap with %w at the end, so the chain prints newest→oldest as outer: middle: inner.%w only when callers need errors.Is / errors.As on the underlying error. Otherwise use %v.%w at the start is for sentinel wrappers only: fmt.Errorf("%w: invalid header", ErrParse). Category first, details after.ErrFoo at package level: var ErrNotFound = errors.New("not found").os.Open errors already include the path — fmt.Errorf("could not open settings.txt: %v", err) is wrong; use a higher-level annotation: fmt.Errorf("launch codes unavailable: %v", err).return err.\n. fmt.Errorf("something bad happened"), not "Something bad happened.".status.Errorf(codes.X, ...) rather than wrapping internal errors raw with %w.error is the last return value. A function taking context.Context should usually return error.For more, see references/errors.md.
error and multiple return values.log.Fatal over panic for terminal conditions in main / init. Fatal does not run deferred functions; that's the point.error at the API edge with a top-level defer recover() that re-panics on unknown payloads.MustX is for package-level vars and tests only. MustParse, template.Must. Not for runtime user input.recover() to suppress crashes. Corrupted state propagates further; better is monitoring + crash + fix.panic("unreachable") after log.Fatalf is the idiom — the compiler doesn't know Fatal doesn't return.For more, see references/panics.md.
assert.Equal, require.NotNil). Use if got != want { t.Errorf(...) }. For complex types: cmp.Equal / cmp.Diff from go-cmp.t.Error over t.Fatal by default — keep going, report all failures in one run. t.Fatal only when continuing is meaningless (setup failed, cascading errors would mislead).t.Run subtests: use t.Fatal to skip just that case. Outside subtests in a table loop: t.Error + continue.t.Fatal (FailNow, Fatalf, SkipNow) from a goroutine other than the test's own. Use t.Error from worker goroutines; t.Fatal only after wg.Wait() from the main goroutine.{name: "empty", input: "", want: ""}.t.Helper() + t.Fatalf. This makes the failure point to the test line, not the helper line.YourFunc(%v) = %v, want %v — function name, inputs, got, want, in that order.For more, see references/tests.md.
:= for non-zero init, var x T for zero values. i := 42, but var coords Point (not coords := Point{}).var t []string, not t := []string{} for empty slices. Empty slice and nil slice behave the same for len, cap, range, append.new(T) vs &T{}: both are fine for zero values; new reads as "zero value placeholder", &T{} is more common when fields are filled.== on nil for slices. Use len(s) == 0. APIs must not distinguish nil from empty.+ for 2–3 short literals; fmt.Sprintf for formatting; strings.Builder in loops; text/template for templates.make([]T, 0, n) / make(map[K]V, n) only when n is known and the code is performance-sensitive. Default to zero-init.if *x { ctx, cancel := ...; } shadows ctx outside the if. Use ctx, cancel = ... with = and var cancel func() declared above.For more, see references/strings-and-vars.md.
context.Context is the first parameter. func F(ctx context.Context, ...) error. Even in test helpers.context.Context in a struct. Pass it through every method that needs it.<-chan T for receive-only, chan<- T for send-only.context.Context in option structs....Option) only when most callers pass nothing, options need parameters, or third parties define options.*string, *io.Reader parameters "to save bytes". Pass values; use pointers for large structs and protobuf messages.For more, see references/api-design.md.
// Encode writes the JSON encoding of req to w.Close, Stop, deferred resources).ctx.Done cancels the function — that's the contract of context.Context.For more, see references/documentation.md.
internal/ for packages not part of the public API.util / common / helper. Name by domain.main or tests.import . ever (in Google codebase).pb suffix: foopb "path/to/foo_go_proto".For more, see references/package-layout.md.
%v vs %w when wrapping an error| Situation | Choose | Why |
|---|---|---|
Caller will errors.Is / errors.As to inspect the chain | %w | Preserves type/sentinel through the chain |
| Crossing an external boundary (RPC, IPC, storage); caller wants canonical codes | %v (or status.Errorf) | Don't leak internal error types over the wire |
| Logging or human-display only; no programmatic inspection | %v | %w adds chain semantics nobody uses |
| Same error is logged here AND returned upward | %v | Wrapping a logged-then-returned error confuses the chain |
Sentinel categorisation first (ErrParse-style) | %w at start: "%w: detail" | Reader sees the category first |
| Adding context around a wrapped error (the common case) | %w at end: "context: %w" | Chain prints newest→oldest naturally: outer: middle: inner |
| Underlying error already carries this info | nothing — return err | Wrapping without adding info is noise |
| Just propagating without analysis | nothing — return err | Don't wrap for the sake of wrapping |
| Situation | Choose | Why |
|---|---|---|
| ≤ 3 parameters, all required, all distinct types | Positional args | Smallest mechanism |
| Many parameters, most callers set most of them | Option struct (last param) | Self-documenting field names; grows without breaking call sites |
| Many parameters, most callers set none | Variadic options (...Option) | Zero overhead at simple call sites |
| Options need failure validation | Variadic options returning error | Can't validate in struct construction |
| Third-party packages must define options | Variadic options with exported Option type | Struct fields can't be extended |
| Same option set used by multiple functions | Option struct | Reuse + share + write helpers on the struct |
context.Context | First positional arg, never in option struct | Convention |
panic vs log.Fatal vs error return| Situation | Choose | Why |
|---|---|---|
| Library detects normal failure | error return | Caller decides |
| Library detects an "impossible" invariant violation | error return or log.Fatal | Caller can't recover anyway |
Bad flag/config in main / init | log.Exit (no stack) | Stack trace useless; user wants the message |
| Internal package consistency check that has been verified by tests | log.Fatal | More reliable than panic (no defer deadlock risk) |
Parser internals that always have a matching recover at the API edge | panic of a private type | Plumbing errors through deep recursion is noise |
| Package-level var initializer needs a value derived from a fallible call | MustX (panics) | Init-time only; init cannot return errors |
| HTTP handler crashes mid-request | never recover() to mask it | State is corrupted; let the process crash and restart |
t.Error vs t.Fatal vs t.Errorf + continue| Situation | Choose |
|---|---|
Multiple independent assertions in one Test*, all should run | t.Error / t.Errorf for each |
| Setup failure — rest of test cannot proceed | t.Fatal / t.Fatalf |
| First failure makes subsequent assertions misleading (e.g. encoded ≠ expected, can't decode meaningfully) | t.Fatalf then continue with t.Errorf |
| Table loop without subtests, this case is broken | t.Errorf + continue |
Inside t.Run(...) subtest, this case is broken | t.Fatal (skips this subtest only) |
| Worker goroutine inside a test | t.Errorf only (NEVER t.Fatal) |
| Test helper called from main test goroutine | t.Helper() + t.Fatalf is fine |
| Situation | Choose | Example |
|---|---|---|
| Initializing with a known non-zero value | := | i := 42 |
| Need a zero value, ready for use | var x T | var coords Point, var s []string |
Need a *T to a zero value | new(T) or &T{} | msg := new(pb.Bar) |
Need a *T to a value with fields | &T{...} | c := &Config{Port: 8080} |
| Empty slice for return / accumulation | var s []T | not s := []T{} |
| Empty map (must be initialized to write) | make(map[K]V) or map[K]V{} | nil map can be read but not written |
| Pre-sized slice/map (perf-sensitive, size known) | make([]T, 0, n) / make(map[K]V, n) | Don't over-pre-allocate |
Load on demand:
references/errors.md — detailed error structure, wrapping rules, sentinels, RPC boundaries, errors.Is/As.references/naming.md — receivers, initialisms, repetition, test doubles, util-package antipattern, shadowing.references/api-design.md — option struct vs variadic options, channel direction, DI, interfaces, generics.references/tests.md — Test funcs vs helpers, table-driven, subtests, goroutines, acceptance testing, cmp.references/panics.md — when allowed (invariants, parsers with recover, init), when forbidden, log.Fatal vs log.Exit.references/documentation.md — godoc conventions, what to document, what to skip, contexts, errors, cleanup.references/package-layout.md — package size, file structure, imports, internal/, side-effect imports.references/strings-and-vars.md — concatenation choices, zero values, size hints, new vs &T{}, shadowing.When in doubt, especially for unusual situations, WebFetch the source section before writing the code. The Google Go Style Guide is the normative authority — this skill is a digest, not a replacement.
For Go fundamentals not covered here, read Effective Go.