Golang Naming
Samuel BertheCommunityCreated by samberDistributed by Samuel Berthe
- Skill
- Guidelines
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides the definitive Go naming standards to ensure code readability and idiomatic consistency. It covers the full spectrum of Go identifiers, including package naming, struct and interface definitions, constructor patterns, error handling, and boolean predicates. By enforcing MixedCaps and avoiding stuttering, it helps developers write code that aligns with the Go community's 'clear is better than clever' philosophy.
What it does
- Defines naming rules for packages, files, and exported/unexported identifiers.
- Provides patterns for constructors, getters, setters, and boolean predicates.
- Explains how to avoid stuttering and redundant naming in Go packages.
- Standardizes error variable naming and error string formatting.
- Offers guidance on acronym casing and receiver naming conventions.
- Outlines conventions for table-driven test functions and subtests.
When to use it
- When writing new Go code and deciding on identifier names.
- During code reviews to identify non-idiomatic naming patterns.
- When refactoring existing code to improve clarity and consistency.
- When debating package structure or naming alternatives like New vs NewTypeName.
- When resolving naming conflicts or choosing between different naming styles.
Advantages
- Promotes idiomatic, readable, and maintainable Go code.
- Reduces cognitive load by enforcing consistent naming across the codebase.
- Prevents common naming pitfalls like stuttering and incorrect acronym casing.
- Aligns code with standard library patterns and community expectations.
Usage examples
- “How should I name a constructor for a struct named 'Client' in a package named 'api'?”
- The skill advises using 'New()' to avoid stuttering, resulting in 'api.New()' instead of 'api.NewClient()'.
- “Should I use 'is_connected' or 'isConnected' for a boolean field in a struct?”
- The skill mandates 'MixedCaps' and 'is' prefixing, confirming 'isConnected' is the correct choice.
- “What is the convention for naming an error variable?”
- The skill specifies using the 'Err' prefix, such as 'ErrNotFound', and keeping error strings fully lowercase.
- “How do I name a getter method for a field named 'port'?”
- The skill instructs to omit the 'Get' prefix, recommending 'Port()' instead of 'GetPort()'.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/samber/golang-naming/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip golang-naming.zip -d .agents/skills
Documentation by samber
Community default. A company skill that explicitly supersedes
samber/cc-skills-golang@golang-namingskill takes precedence.
Go Naming Conventions
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.
Quick Reference
| Element | Convention | Example |
|---|---|---|
| Package | lowercase, single word, _test suffix OK for test files | json, http, tabwriter, http_test |
| File | lowercase, underscores OK | user_handler.go |
| Exported name | UpperCamelCase | ReadAll, HTTPClient |
| Unexported | lowerCamelCase | parseToken, userCount |
| Interface | method name + -er | Reader, Closer, Stringer |
| Struct | MixedCaps noun | Request, FileHeader |
| Constant | MixedCaps (not ALL_CAPS) | MaxRetries, defaultTimeout |
| Receiver | 1-2 letter abbreviation | func (s *Server), func (b *Buffer) |
| Error variable | Err prefix | ErrNotFound, ErrTimeout |
| Error type | Error suffix | PathError, SyntaxError |
| Constructor | New (single type) or NewTypeName (multi-type) | ring.New, http.NewRequest |
| Boolean field | is, has, can prefix on fields and methods | isReady, IsConnected() |
| Test function | Test + function name | TestParseToken |
| Acronym | all caps or all lower | URL, HTTPServer, xmlParser |
| Variant: context | WithContext suffix | FetchWithContext, QueryContext |
| Variant: in-place | In suffix | SortIn(), ReverseIn() |
| Variant: error | Must prefix | MustParse(), MustLoadConfig() |
| Option func | With + field name | WithPort(), WithLogger() |
| Enum (iota) | type name prefix, zero-value = unknown | StatusUnknown at 0, StatusReady |
| Named return | descriptive, for docs only | (n int, err error) |
| Error string | lowercase (incl. acronyms), no punctuation | "image: unknown format", "invalid id" |
| Import alias | short, only on collision | mrand "math/rand", pb "app/proto" |
| Format func | f suffix | Errorf, Wrapf, Logf |
| Test table fields | got/expected prefixes | input string, expected int |
MixedCaps
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.
// ✓ 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 notationAvoid Stuttering
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.
// 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 PoolOptionFrequently Missed Conventions
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".
Detailed Categories
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:
ifor 3-line loops, longer names for package-level), single-letter receiver conventions (sfor Server), acronym casing (URL not Url, HTTPServer not HttpServer), and boolean naming patterns (isReady, hasPrefix).Functions, Methods & Options — Getter/setter patterns (Go omits
Getsouser.Name()reads naturally), constructor conventions (NeworNewTypeName), named returns (for documentation only), format function suffixes (Errorf,Wrapf), and functional options (WithPort,WithLogger).Types, Constants & Errors — Interface naming (
Reader,Closersuffix with-er), struct naming (nouns, MixedCaps), constants (MixedCaps, not ALL_CAPS), enums (type name prefix likeStatusReady), sentinel errors (ErrNotFoundvariables), error types (PathErrorsuffix), 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.
Common Mistakes
| Mistake | Fix |
|---|---|
ALL_CAPS constants | Go reserves casing for visibility, not emphasis — use MixedCaps (MaxRetries) |
GetName() getter | Go 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 acronyms | Mixed-case acronyms create ambiguity (HttpsUrl — is it Https+Url?). Use all caps or all lower |
this or self receiver | Go methods are called frequently — use 1-2 letter abbreviation (s for Server) to reduce visual noise |
util, helper packages | These names say nothing about content — use specific names that describe the abstraction |
http.HTTPClient stuttering | Package name is always present at call site — http.Client avoids reading "HTTP" twice |
user.NewUser() constructor | Single primary type uses New() — user.New() avoids repeating the type name |
connected bool field | Bare adjective is ambiguous — use isConnected so the field reads as a true/false question |
"invalid message ID" error | Error strings must be fully lowercase including acronyms — "invalid message id" |
StatusReady at iota 0 | Zero value should be a sentinel — StatusUnknown at 0 catches uninitialized values |
"not found" error string | Sentinel errors should include the package name — "mypackage: not found" identifies the origin |
userSlice type-in-name | Types encode implementation detail — users describes what it holds, not how |
| Inconsistent receiver names | Switching names across methods of the same type confuses readers — use one name consistently |
snake_case identifiers | Underscores conflict with Go's MixedCaps convention and tooling expectations — use mixedCaps |
| Long names for short scopes | Name length should match scope — i is fine for a 3-line loop, userIndex is noise |
| Naming constants by value | Values change, roles don't — DefaultPort survives a port change, Port8080 doesn't |
FetchCtx() context variant | WithContext is the standard Go suffix — FetchWithContext() is instantly recognizable |
sort() in-place but no In | Readers assume functions return new values. SortIn() signals mutation |
parse() panicking on error | MustParse() warns callers that failure panics — surprises belong in the name |
Mixing With*, Set*, Use* | Consistency across the codebase — With* is the Go convention for functional options |
| Plural package names | Go convention is singular (net/url not net/urls) — keeps import paths consistent |
Wrapf without f suffix | The f suffix signals format-string semantics — Wrapf, Errorf tell callers to pass format args |
| Unnecessary import aliases | Aliases add cognitive load. Only alias on collision — mrand "math/rand" |
| Inconsistent concept names | Using 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.
Enforce with Linters
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.
Cross-References
→ See
samber/cc-skills-golang@golang-code-styleskill for broader formatting and style decisions→ See
samber/cc-skills-golang@golang-structs-interfacesskill for interface naming depth and receiver design→ See
samber/cc-skills-golang@golang-lintskill for automated enforcement (revive, predeclared, misspell, errname)→ See
samber/cc-skills-golang@golang-goplsskill for safe rename when applying a naming fix→ See
samber/cc-skills-golang@golang-refactoringskill 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
Files
- ATTRIBUTION.mdAdded by AutoGineer896 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md12.3 KiB
- evals/evals.json28.0 KiB
- references/functions-methods.md4.2 KiB
- references/identifiers.md5.4 KiB
- references/packages-files.md3.0 KiB
- references/testing.md1.2 KiB
- references/types-errors.md4.5 KiB
references/identifiers.md
Variables, Booleans, Receivers & Acronyms
Table of Contents
Variables
Avoid Type in the Name
Avoid Repetition with Context
Use Predictable Names
Parameters
Booleans
Receivers
Acronyms and Initialisms
Variables
Name length SHOULD be proportional to scope size. Short names for small scopes, descriptive names for large scopes.
// Small scope (1-7 lines): short names are fine
for i, v := range items {
result = append(result, v.Name)
}
// Medium scope: moderately descriptive
userCount := len(users)
// Large scope / package-level: explicit and clear
var defaultHTTPTransport = &http.Transport{
MaxIdleConns: 100,
}Common single-letter conventions:
| Letter | Meaning |
|---|---|
i, j, k | Loop indices |
n | Count or length |
v | Value (in range loops) |
k | Key (in map ranges) |
r | io.Reader |
w | io.Writer |
b | []byte or buffer |
s | String |
t | *testing.T |
ctx | context.Context |
err | Error |
Avoid Type in the Name
The name should describe what the value represents, not its type.
// Good
users := getUsers()
count := len(items)
// Bad
userSlice := getUsers()
countInt := len(items)
nameString := "hello"Avoid Repetition with Context
Omit words already clear from the enclosing function, method, or type.
// Good — "user" is clear from the method receiver
func (u *UserService) Create(name string) error { ... }
// Bad — "user" is redundant
func (u *UserService) CreateUser(userName string) error { ... }Use Predictable Names
The same concept MUST always use the same name across the codebase. If a user is called user in one function, it should not become account, person, or u in another. Consistency makes code searchable and reduces cognitive load.
// Good — same concept, same name everywhere
func CreateUser(user *User) error { ... }
func UpdateUser(user *User) error { ... }
func DeleteUser(userID string) error { ... }
// Bad — same concept, different names
func CreateUser(user *User) error { ... }
func UpdateAccount(acct *User) error { ... } // why "acct"? it's a User
func RemovePerson(id string) error { ... } // why "person"? why "remove"?This applies to variables, parameters, functions, and fields. Pick one name per domain concept and stick with it: order not sometimes order / sometimes purchase; userID not sometimes userID / sometimes uid / sometimes userId.
Parameters
Parameters double as documentation at the call site. When the type is descriptive, keep the name short. When the type is ambiguous, use a longer name to clarify intent.
// Good — type is descriptive, short name is fine
func AfterFunc(d Duration, f func()) *Timer
func Escape(w io.Writer, s []byte)
// Good — type is ambiguous (int64, string), longer name documents meaning
func Unix(sec, nsec int64) Time
func HasPrefix(s, prefix string) bool
// Bad — ambiguous type with cryptic name
func Unix(a, b int64) Time // what are a and b?
func HasPrefix(a, b string) bool // which is the prefix?Booleans
Boolean variables and fields MUST read naturally as true/false questions. Use prefixes like is, has, can, allow, should. This applies to both variables and struct fields.
// Good — struct fields use is/has prefix
type Client struct {
isConnected bool // reads as "client is connected"
hasPermission bool // reads as "client has permission"
}
// Good — variables
isReady := true
hasPermission := user.CanEdit(doc)
// Bad — bare adjective is ambiguous
type Client struct {
connected bool // could be confused with a connection object
permission bool // noun, not a question
}For exported boolean methods, the prefix becomes part of the method name: IsValid(), HasPrefix(), CanRetry(). The unexported field keeps the prefix too: isConnected field → IsConnected() method.
Receivers
Receivers MUST be 1-2 letter abbreviations of the type name. Use the same name across all methods of a type.
// Good — short, consistent
func (s *Server) Start() error { ... }
func (s *Server) Stop() error { ... }
func (s *Server) Handle(r *Request) { ... }
// Bad — too long
func (server *Server) Start() error { ... }
// Bad — inconsistent names across methods
func (s *Server) Start() error { ... }
func (srv *Server) Stop() error { ... }
// Bad — NEVER use "this" or "self"
func (this *Server) Handle(r *Request) { ... }Acronyms and Initialisms
Acronyms MUST be all caps or all lower, NEVER mixed. This preserves readability in MixedCaps names.
// Good
URL // all caps
url // all lower
HTTPServer // HTTP is all caps
xmlParser // xml is all lower
userID // ID is all caps
newHTTPSURL // both HTTPS and URL all caps
// Bad
Url // mixed case acronym
HttpServer // mixed case
userId // mixed case for IDWhen exporting a lowercase acronym, capitalize the whole thing: url → URL, grpc → GRPC, ios → IOS.
Requirements and compatibility
Written for: Claude Code, OpenAI Codex
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Declares allowed tools, Claude Code frontmatter
The author says: Designed for Claude Code, Codex or similar harness, and for projects using Golang.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- samber
- Publisher
- Samuel Berthe (Community)
- Distributed by
- Samuel Berthe
- Source
- samber/cc-skills-golang · skills/golang-naming · commit bb1d43d
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by samber or Samuel Berthe.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download golang-naming.zip