In Go the package name is part of every call site, capitalization decides visibility, and short names are the norm. A good name reads well where it is used, not where it is declared.
Community default. A project skill or agent-config rule that explicitly supersedes
go-namingtakes precedence over this one.
Detailed reference material, loaded on demand:
references/examples.md— before/after renames for every rule below, including the initialism and stuttering edge cases.
Read a reference file only when the summary below is not enough.
1. Quick Reference
| Element | Convention | Example |
|---|---|---|
| Package | short, lowercase, one word, singular | order, httpsign, postgres |
| File | lowercase, _ allowed, named after its main type or concern |
order_service.go, order_service_test.go |
| Exported identifier | MixedCaps |
ParseToken, MaxRetries |
| Unexported identifier | mixedCaps |
parseToken, maxRetries |
| Initialism | all one case | URL, userID, ServeHTTP, xmlParser |
| Getter / setter | Owner() / SetOwner() |
never GetOwner() |
| Constructor | New for the package's main type, NewThing otherwise |
ring.New, http.NewRequest |
| Panicking variant | Must prefix |
template.Must, regexp.MustCompile |
| Functional option | With + setting |
WithTimeout, WithLogger |
| One-method interface | method + -er |
Reader, Notifier |
| Receiver | 1-2 letters, same on every method | func (s *Server) |
| Sentinel error | Err prefix (err unexported) |
ErrNotFound, errClosed |
| Error type | Error suffix |
ValidationError |
| Enum constant | type name prefix, zero = unknown | StatusUnknown, StatusActive |
| Test | Test + function, Test + type _ method |
TestParse, TestCache_Get |
2. Packages
- Short, lowercase, single word: no underscores, no
mixedCaps, no plural (order, notorders). - Name it after what it provides:
retry,httpsign,postgres. Neverutil,common,helpers,misc,base,models,types— they say nothing and collect everything. - The directory name and the package name match.
- Avoid names callers want for their variables (
url,user,buf) when the package is imported widely; a call site withu := user.New()reads better than shadowing the package.
3. Don't Stutter
The package name is always present at the call site, so don't repeat it:
// ✅ Good — reads once
http.Client order.Service user.New() config.Load()
// ❌ Bad — says it twice
http.HTTPClient order.OrderService user.NewUser() config.LoadConfig()
The rule covers every exported name in the package, not just the main
type: in package dbpool, Pool, Status and Option — not DBPool,
PoolStatus, PoolOption.
4. MixedCaps, Initialisms and Constants
- Every identifier is
MixedCapsormixedCaps. Underscores appear only in test names (TestCache_Get), generated code, and cgo. - An initialism keeps one case throughout:
URL,ID,HTTP,JSON,API—userID,parseURL,ServeHTTP,HTTPServer,xmlHTTPRequest. NeverUserId,ParseUrl,HttpServer. - Constants are
MixedCapslike everything else:MaxRetries, notMAX_RETRIES— case already means "exported" in Go. - Name constants for their role, not their value:
DefaultPort, notPort8080. - Do not shadow predeclared identifiers:
len,cap,new,make,close,copy,error,string,min,max.
5. Functions and Methods
- Getters drop
Get:u.Name(), and the setter isu.SetName().Is/Has/Canstay on boolean predicates:IsActive(). - Constructors:
Newwhen the package has one main type,NewThingotherwise. A constructor that panics on bad input isMustThing. - Canonical names carry a contract. Call a method
Read,Write,Close,Flush,String,ErrororServeHTTPonly if it has the standard signature and meaning — and if it does, use that name (String(), neverToString()). - Name for what the caller gets, not how it is computed:
Users(), notQueryAndBuildUserList(). - Format-string variants end in
f:Errorf,Logf.
6. Variables and Receivers
- Name length grows with scope:
i,n,err,ctx,bufinside a few lines;retryTimeout,pendingOrdersacross a function; full words at package level. - Don't put the type in the name (
userSlice→users,nameStr→name), and don't repeat context the reader already has (order.IDinsidetype Order, notorder.OrderID). - Receivers are one or two letters from the type (
s *Server,rw *responseWriter), the same on every method of the type — neverthisorself. - Unexported package-level variables may take a
_prefix (_defaultTimeout) to keep them distinct from locals — the Uber style convention. Follow whichever the codebase already uses. - Boolean names read as a question:
isReady,hasChildren,canRetry.
7. Types and Interfaces
- Types are nouns:
Request,FileHeader,RetryPolicy. - A one-method interface is the method plus
-er:Reader,Notifier,Validator. Never anIprefix orInterfacesuffix. - Name an interface after the behavior the consumer needs, in the
consumer's package (
orderStorein the service), not after the implementation it happens to have.
8. Errors
- Exported sentinels
ErrNotFound, unexportederrClosed. - Error types end in
Error:NotFoundError,SyntaxError. - Error strings are lowercase with no trailing punctuation, prefixed with
the package or operation:
"order: invalid quantity". They get wrapped into longer messages, so they must read mid-sentence.
9. Enums and Tests
- Enum constants are prefixed with their type and start with an explicit
Unknownat zero:StatusUnknown,StatusActive,StatusClosed. - Tests:
TestParse,TestCache_Get,BenchmarkParse,ExampleCache_Get(the example name must match a real identifier, orgo vetcomplains). - Subtest names are short lowercase phrases —
"empty input","expired token"— becausego test -run 'TestParse/empty_input'selects them.
Applying a Rename
Rename with gopls, not search-and-replace: it follows the type graph and refuses renames that would break interface satisfaction (the go-semantic-tools skill). Then grep struct tags, templates and SQL for the old name — gopls does not see them. Exported names in a published library need a deprecation cycle (the go-refactoring skill).
Verification Checklist
- No package named
util,common,helpers,models,types,miscorbase - No exported name repeats its package name
- Initialisms keep one case (
ID,URL,HTTP); noALL_CAPSconstants - No
Getprefix on getters;Mustonly on panicking functions - Canonical method names (
String,Read,Close, …) have canonical signatures - Receivers are short and identical across a type's methods; no
this/self - Sentinels use
Err, error types end inError, error strings are lowercase - Enum constants carry the type prefix and an
Unknownzero value - No predeclared identifier is shadowed
- Renames done with gopls; tags and templates checked afterwards