Community default. A company skill that explicitly supersedes
samber/cc-skills-golang@golang-namingskill takes precedence.
Go favors short, readable names. Capitalization controls visibility — uppercase is exported, lowercase is unexported. All identifiers MUST use MixedCaps, NEVER underscores.
"Clear is better than clever." — Go Proverbs
"Design the architecture, name the components, document the details." — Go Proverbs
To ignore a rule, just add a comment to the code.
ElementConventionExamplePackagelowercase, single word, _test suffix OK for test filesjson, http, tabwriter, http_testFilelowercase, underscores OKuser_handler.goExported nameUpperCamelCaseReadAll, HTTPClientUnexportedlowerCamelCaseparseToken, userCountInterfacemethod name + -er``Reader, Closer, StringerStructMixedCaps nounRequest, FileHeaderConstantMixedCaps (not ALL_CAPS)MaxRetries, defaultTimeoutReceiver1-2 letter abbreviationfunc (s *Server), func (b *Buffer)Error variableErr prefixErrNotFound, ErrTimeoutError typeError suffixPathError, SyntaxErrorConstructorNew (single type) or NewTypeName (multi-type)ring.New, http.NewRequestBoolean fieldis, has, can prefix on fields and methodsisReady, IsConnected()Test functionTest + function nameTestParseTokenAcronymall caps or all lowerURL, HTTPServer, xmlParserVariant: contextWithContext suffixFetchWithContext, QueryContextVariant: in-placeIn suffixSortIn(), ReverseIn()Variant: errorMust prefixMustParse(), MustLoadConfig()Option funcWith + field nameWithPort(), WithLogger()Enum (iota)type name prefix, zero-value = unknownStatusUnknown at 0, StatusReadyNamed returndescriptive, for docs only(n int, err error)Error stringlowercase (incl. acronyms), no punctuation"image: unknown format", "invalid id"Import aliasshort, only on collisionmrand "math/rand", pb "app/proto"Format funcf suffixErrorf, Wrapf, LogfTest table fieldsgot/ expected prefixesinput string, expected int
All Go identifiers MUST use MixedCaps (or mixedCaps). NEVER use underscores in identifiers — the only exceptions are test function subcases ( TestFoo_InvalidInput), generated code, and OS/cgo interop. This is load-bearing, not cosmetic — Go's export mechanism relies on capitalization, and tooling assumes MixedCaps throughout.
go
// ✓ Good
MaxPacketSize
userCount
parseHTTPResponse
// ✗ Bad — these conventions conflict with Go's export mechanism and tooling expectations
MAX_PACKET_SIZE // C/Python style
max_packet_size // snake_case
kMaxBufferSize // Hungarian notation
Go call sites always include the package name, so repeating it in the identifier wastes the reader's time — http.HTTPClient forces parsing "HTTP" twice. A name MUST NOT repeat information already present in the package name, type name, or surrounding context.
go
// Good — clean at the call site
http.Client // not http.HTTPClient
json.Decoder // not json.JSONDecoder
user.New() // not user.NewUser()
config.Parse() // not config.ParseConfig()
// In package sqldb:
type Connection struct{} // not DBConnection — "db" is already in the package name
// Anti-stutter applies to ALL exported types, not just the primary struct:
// In package dbpool:
type Pool struct{} // not DBPool
type Status struct{} // not PoolStatus — callers write dbpool.Status
type Option func(*Pool) // not PoolOption
These conventions are correct but non-obvious — they are the most common source of naming mistakes:
Constructor naming: When a package exports a single primary type, the constructor is New(), not NewTypeName(). This avoids stuttering — callers write apiclient.New() not apiclient.NewClient(). Use NewTypeName() only when a package has multiple constructible types (like http.NewRequest, http.NewServeMux).
Boolean struct fields: Unexported boolean fields MUST use is/ has/ can prefix — isConnected, hasPermission, not bare connected or permission. The exported getter keeps the prefix: IsConnected() bool. This reads naturally as a question and distinguishes booleans from other types.
Error strings are fully lowercase — including acronyms. Write "invalid message id" not "invalid message ID", because error strings are often concatenated with other context ( fmt.Errorf("parsing token: %w", err)) and mixed case looks wrong mid-sentence. Sentinel errors should include the package name as prefix: errors.New("apiclient: not found").
Enum zero values: Always place an explicit Unknown/ Invalid sentinel at iota position 0. A var s Status silently becomes 0 — if that maps to a real state like StatusReady, code can behave as if a status was deliberately chosen when it wasn't.
Subtest names: Table-driven test case names in t.Run() should be fully lowercase descriptive phrases: "valid id", "empty input" — not "valid ID" or "Valid Input".
For complete rules, examples, and rationale, see:
Packages, Files & Import Aliasing — Package naming (single word, lowercase, no plurals), file naming conventions, import alias patterns (only use on collision to avoid cognitive load), and directory structure.
Variables, Booleans, Receivers & Acronyms — Scope-based naming (length matches scope: i for 3-line loops, longer names for package-level), single-letter receiver conventions ( s for Server), acronym casing (URL not Url, HTTPServer not HttpServer), and boolean naming patterns (isReady, hasPrefix).
Functions, Methods & Options — Getter/setter patterns (Go omits Get so user.Name() reads naturally), constructor conventions ( New or NewTypeName), named returns (for documentation only), format function suffixes ( Errorf, Wrapf), and functional options ( WithPort, WithLogger).
Types, Constants & Errors — Interface naming ( Reader, Closer suffix with -er), struct naming (nouns, MixedCaps), constants (MixedCaps, not ALL_CAPS), enums (type name prefix like StatusReady), sentinel errors ( ErrNotFound variables), error types ( PathError suffix), and error message conventions (lowercase, no punctuation).
Test Naming — Test function naming ( TestFunctionName), table-driven test field conventions ( input, expected), test helper naming, and subcase naming patterns.
MistakeFixALL_CAPS constantsGo reserves casing for visibility, not emphasis — use MixedCaps ( MaxRetries)GetName() getterGo omits Get because user.Name() reads naturally at call sites. But Is/ Has/ Can prefixes are kept for boolean predicates: IsHealthy() bool not Healthy() bool``Url, Http, Json acronymsMixed-case acronyms create ambiguity ( HttpsUrl — is it Https+Url?). Use all caps or all lowerthis or self receiverGo methods are called frequently — use 1-2 letter abbreviation ( s for Server) to reduce visual noiseutil, helper packagesThese names say nothing about content — use specific names that describe the abstractionhttp.HTTPClient stutteringPackage name is always present at call site — http.Client avoids reading "HTTP" twiceuser.NewUser() constructorSingle primary type uses New() — user.New() avoids repeating the type nameconnected bool fieldBare adjective is ambiguous — use isConnected so the field reads as a true/false question"invalid message ID" errorError strings must be fully lowercase including acronyms — "invalid message id"``StatusReady at iota 0Zero value should be a sentinel — StatusUnknown at 0 catches uninitialized values"not found" error stringSentinel errors should include the package name — "mypackage: not found" identifies the originuserSlice type-in-nameTypes encode implementation detail — users describes what it holds, not howInconsistent receiver namesSwitching names across methods of the same type confuses readers — use one name consistentlysnake_case identifiersUnderscores conflict with Go's MixedCaps convention and tooling expectations — use mixedCapsLong names for short scopesName length should match scope — i is fine for a 3-line loop, userIndex is noiseNaming constants by valueValues change, roles don't — DefaultPort survives a port change, Port8080 doesn'tFetchCtx() context variantWithContext is the standard Go suffix — FetchWithContext() is instantly recognizablesort() in-place but no InReaders assume functions return new values. SortIn() signals mutationparse() panicking on errorMustParse() warns callers that failure panics — surprises belong in the nameMixing With*, Set*, Use*Consistency across the codebase — With* is the Go convention for functional optionsPlural package namesGo convention is singular ( net/url not net/urls) — keeps import paths consistentWrapf without f suffixThe f suffix signals format-string semantics — Wrapf, Errorf tell callers to pass format argsUnnecessary import aliasesAliases add cognitive load. Only alias on collision — mrand "math/rand"Inconsistent concept namesUsing user/ account/ person for the same concept forces readers to track synonyms — pick one name
Applying these fixes means renaming existing identifiers — → See samber/cc-skills-golang@golang-gopls skill to do it safely: its rename updates every call site across the workspace and refuses a rename that would break interface satisfaction, which a grep/sed or manual Edit-based rename silently misses.
Many naming convention issues are caught automatically by linters: revive, predeclared, misspell, errname. See samber/cc-skills-golang@golang-lint skill for configuration and usage.
samber/cc-skills-golang@golang-code-style skill for broader formatting and style decisionssamber/cc-skills-golang@golang-structs-interfaces skill for interface naming depth and receiver designsamber/cc-skills-golang@golang-lint skill for automated enforcement (revive, predeclared, misspell, errname)samber/cc-skills-golang@golang-gopls skill for safe rename when applying a naming fixsamber/cc-skills-golang@golang-refactoring skill for how to apply a rename safely at scale (gopls Rename/Inline, blast-radius mapping, staged PR workflow) once you've decided what to rename identifiers to