golang-design-patterns
Skill2 starsChanged 29 days agoMITView on GitHub
Idiomatic Golang design patterns — functional options, constructors, error flow and cascading, resource management and lifecycle, graceful shutdown, resilience, architecture, dependency injection, data handling, streaming, and more. Apply when explicitly choosing between architectural patterns, implementing functional options, designing constructor APIs, setting up graceful shutdown, applying resilience patterns, or asking which idiomatic Go pattern fits a specific problem.
- Installs packages
16 other projects use a version of this, 11 of them edited.
Adopted by
Most recently taken up by
- aiproxer/aiproxertheir own version, first seen Nov 8, 2026
- samber/cc-skills-golangedited, first seen Nov 1, 2026
- poizoncoded/skillsedited, first seen Nov 1, 2026
- damacus/agent-skillsedited, first seen Oct 29, 2026
- klawisha012/agentsyncedited, first seen Oct 25, 2026
- rockcookies/skillsedited, first seen Oct 13, 2026
Other versions16 projects use a version of this.
Word for word · 2
- alexastrum/skl★ 11100% same
- VerifiedOrganic/onboard★ 1100% same
Edited · 11
- samber/cc-skills-golang★ 3.8k92% same
- unxed/f4★ 26192% same
- klawisha012/agentsync★ 1898% same
- tstapler/dotfiles★ 898% same
- tquangkhai98/browser-profiles-manager★ 596% same
- damacus/agent-skills★ 292% same
- poizoncoded/skills★ 298% same
- rockcookies/skills★ 192% same
- gccli/skills★ 097% same
- guynhsichngeodiec/cc-skills-golang★ 097% same
1 more not listed
Wrote their own version · 3
- aiproxer/aiproxer★ 22same name
- saifoelloh/golang-best-practices-skill★ 15same name
- reagin/agent-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository192 other files it gives its agents.
- clickhouse-architecture-advisor/AGENTS.mdAGENTS.md
- clickhouse-best-practices/AGENTS.mdAGENTS.md
- unsafe-checker/AGENTS.mdAGENTS.md
- alertmanager-querySkill
- analyzing-range-distributionSkill
- analyzing-schema-change-storage-riskSkill
- argocdSkill
- aspire-configurationSkill
- aspire-integration-testingSkill
- aspire-service-defaultsSkill
- auditing-cloud-cluster-securitySkill
- auditing-table-statisticsSkill
- benchmarking-transaction-patternsSkill
- cepthSkill
- chdb-datastoreSkill
- chdb-sqlSkill
- clickhouse-architecture-advisorSkill
- clickhouse-best-practicesSkill
- clickhousectl-cloud-deploySkill
- clickhousectl-local-devSkill
- cockroachdb-sqlSkill
- coding-guidelinesSkill
- configuring-audit-loggingSkill
- configuring-ip-allowlistsSkill
- configuring-log-exportSkill
- configuring-private-connectivitySkill
- configuring-sso-and-scimSkill
- create-technical-architecture-documentSkill
- csharp-mstestSkill
- csharp-tunitSkill
- csharp-xunitSkill
- designing-application-transactionsSkill
- designing-multi-region-applicationsSkill
- domain-cliSkill
- domain-cloud-nativeSkill
- domain-embeddedSkill
- domain-fintechSkill
- domain-iotSkill
- domain-mlSkill
- domain-webSkill
- dotnet-aot-wasmSkill
- dotnet-aspire-patternsSkill
- dotnet-benchmarkdotnetSkill
- dotnet-blazor-authSkill
- dotnet-blazor-componentsSkill
- dotnet-blazor-patternsSkill
- dotnet-blazor-testingSkill
- dotnet-channelsSkill
- dotnet-ci-benchmarkingSkill
- dotnet-cli-architectureSkill
- dotnet-cli-distributionSkill
- dotnet-cli-packagingSkill
- dotnet-cli-release-pipelineSkill
- dotnet-containersSkill
- dotnet-cryptographySkill
- dotnet-csharp-dependency-injectionSkill
- dotnet-csharp-modern-patternsSkill
- dotnet-csharp-nullable-reference-typesSkill
- dotnet-csharp-source-generatorsSkill
- dotnet-maui-doctorSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
5 rules. 4 are common, 0 are distinctive, and 1 is very specific to this project.
4
Common
Most of the 14 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Common: line 43
Every external call SHOULD have a timeout — a slow upstream hangs your goroutine indefinitely
- Very specific: line 184
.Close()/Flush()errors: read-only cleanup can often use defer f.Close(), but write/flush resources must report close or flush errors … - Common: line 196
Avoid repeated conversions — each one allocates.
- Common: line 200
Use iterators (Go 1.23+) and streaming patterns to process large datasets without loading everything into memory.
- Common: line 245
Ask the developer which architecture they prefer: clean architecture, hexagonal, DDD, or flat layout.
“Common” is measured: kept by at least 6 in 10 of the 14 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Persona: You are a Go architect who values simplicity and explicitness. You apply patterns only when they solve a real problem — not to demonstrate sophistication — and you push back on premature abstraction.
Modes:
- Design mode — creating new APIs, packages, or application structure: ask the developer about their architecture preference before proposing patterns; favor the smallest pattern that satisfies the requirement.
- Review mode — auditing existing code for design issues: scan for
init()abuse, unbounded resources, missing timeouts, and implicit global state; report findings before suggesting refactors.
Community default. A company skill that explicitly supersedes
samber/cc-skills-golang@golang-design-patternsskill takes precedence.
Go Design Patterns & Idioms
Idiomatic Go patterns for production-ready code. For error handling details see the samber/cc-skills-golang@golang-error-handling skill; for context propagation see samber/cc-skills-golang@golang-context skill; for struct/interface design see samber/cc-skills-golang@golang-structs-interfaces skill.
Best Practices Summary
- Constructors SHOULD use functional options — they scale better as APIs evolve (one function per option, no breaking changes)
- Functional options MUST return an error if validation can fail — catch bad config at construction, not at runtime
- Avoid
init()— runs implicitly, cannot return errors, makes testing unpredictable. Use explicit constructors - Enums SHOULD start at 1 (or Unknown sentinel at 0) — Go's zero value silently passes as the first enum member
- Error cases MUST be handled first with early return — keep happy path flat
- Panic is for bugs, not expected errors — callers can handle returned errors; panics crash the process
defer Close()immediately after opening — later code changes can accidentally skip cleanupruntime.AddCleanupoverruntime.SetFinalizer— finalizers are unpredictable and can resurrect objects- Every external call SHOULD have a timeout — a slow upstream hangs your goroutine indefinitely
- Limit everything (pool sizes, queue depths, buffers) — unbounded resources grow until they crash
- Retry logic MUST check context cancellation between attempts
- Use
strings.Builderfor concatenation in loops → seesamber/cc-skills-golang@golang-code-style - string vs []byte: use
[]bytefor mutation and I/O,stringfor display and keys — conversions allocate - Iterators (Go 1.23+): use for lazy evaluation — avoid loading everything into memory
- Stream large transfers — loading millions of rows causes OOM; stream keeps memory constant
//go:embedfor static assets — embeds at compile time, eliminates runtime file I/O errors- Use
crypto/randfor keys/tokens —math/randis predictable → seesamber/cc-skills-golang@golang-security - Regexp MUST be compiled once at package level — compilation is O(n) and allocates
- Compile-time interface checks:
var _ Interface = (*Type)(nil) - A little recode > a big dependency — each dep adds attack surface and maintenance burden
- Design for testability — accept interfaces, inject dependencies
Constructor Patterns: Functional Options vs Builder
Functional Options (Preferred)
type Server struct {
addr string
readTimeout time.Duration
writeTimeout time.Duration
maxConns int
}
type Option func(*Server)
func WithReadTimeout(d time.Duration) Option {
return func(s *Server) { s.readTimeout = d }
}
func WithWriteTimeout(d time.Duration) Option {
return func(s *Server) { s.writeTimeout = d }
}
func WithMaxConns(n int) Option {
return func(s *Server) { s.maxConns = n }
}
func NewServer(addr string, opts ...Option) *Server {
// Default options
s := &Server{
addr: addr,
readTimeout: 5 * time.Second,
writeTimeout: 10 * time.Second,
maxConns: 100,
}
for _, opt := range opts {
opt(s)
}
return s
}
// Usage
srv := NewServer(":8080",
WithReadTimeout(30*time.Second),
WithMaxConns(500),
)Constructors SHOULD use functional options — they scale better with API evolution and require less code. Use builder pattern only if you need complex validation between configuration steps.
Constructors & Initialization
Avoid init() and Mutable Globals
init() runs implicitly, makes testing harder, and creates hidden dependencies:
- Multiple
init()functions run in declaration order, across files in filename alphabetical order — fragile - Cannot return errors — failures must panic or
log.Fatal - Runs before
main()and tests — side effects make tests unpredictable
// Bad — hidden global state
var db *sql.DB
func init() {
var err error
db, err = sql.Open("postgres", os.Getenv("DATABASE_URL"))
if err != nil {
log.Fatal(err)
}
}
// Good — explicit initialization, injectable
func NewUserRepository(db *sql.DB) *UserRepository {
return &UserRepository{db: db}
}Enums: Start at 1
Zero values should represent invalid/unset state:
type Status int
const (
StatusUnknown Status = iota // 0 = invalid/unset
StatusActive // 1
StatusInactive // 2
StatusSuspended // 3
)Compile Regexp Once
// Good — compiled once at package level
var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
func ValidateEmail(email string) bool {
return emailRegex.MatchString(email)
}Use //go:embed for Static Assets
import "embed"
//go:embed templates/*
var templateFS embed.FS
//go:embed version.txt
var version stringCompile-Time Interface Checks
→ See samber/cc-skills-golang@golang-structs-interfaces for the var _ Interface = (*Type)(nil) pattern.
Error Flow Patterns
Error cases MUST be handled first with early return — keep the happy path at minimal indentation. → See samber/cc-skills-golang@golang-code-style for the full pattern and examples.
When to Panic vs Return Error
- Return error: network failures, file not found, invalid input — anything a caller can handle
- Panic: nil pointer in a place that should be impossible, violated invariant,
Must*constructors used at init time .Close()/Flush()errors: read-only cleanup can often usedefer f.Close(), but write/flush resources must report close or flush errors when durability matters
Data Handling
string vs []byte vs []rune
| Type | Default for | Use when |
string | Everything | Immutable, safe, UTF-8 |
[]byte | I/O | Writing to io.Writer, building strings, mutations |
[]rune | Unicode ops | len() must mean characters, not bytes |
Avoid repeated conversions — each one allocates. Stay in one type until you need the other.
Iterators & Streaming for Large Data
Use iterators (Go 1.23+) and streaming patterns to process large datasets without loading everything into memory. For large transfers between services (e.g., 1M rows DB to HTTP), stream to prevent OOM.
For code examples, see Data Handling Patterns.
Resource Management
defer Close() immediately after opening — don't wait, don't forget:
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close() // right here, not 50 lines later
rows, err := db.QueryContext(ctx, query)
if err != nil {
return err
}
defer rows.Close()For graceful shutdown, resource pools, and runtime.AddCleanup, see Resource Management.
Resilience & Limits
Timeout Every External Call
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
resp, err := httpClient.Do(req.WithContext(ctx))Retry & Context Checks
Retry logic MUST check ctx.Err() between attempts and use exponential/linear backoff via select on ctx.Done(). Long loops MUST check ctx.Err() periodically. → See samber/cc-skills-golang@golang-context skill.
Database Patterns
→ See samber/cc-skills-golang@golang-database skill for sqlx/pgx, transactions, nullable columns, connection pools, repository interfaces, testing.
Architecture
Ask the developer which architecture they prefer: clean architecture, hexagonal, DDD, or flat layout. Don't impose complex architecture on a small project.
Core principles regardless of architecture:
- Keep domain pure — no framework dependencies in the domain layer
- Fail fast — validate at boundaries, trust internal code
- Make illegal states unrepresentable — use types to enforce invariants
- Respect 12-factor app principles — → see
samber/cc-skills-golang@golang-project-layout
Detailed Guides
| Guide | Scope |
| Architecture Patterns | High-level principles, when each architecture fits |
| Clean Architecture | Use cases, dependency rule, layered adapters |
| Hexagonal Architecture | Ports and adapters, domain core isolation |
| Domain-Driven Design | Aggregates, value objects, bounded contexts |
Code Philosophy
- Avoid repetitive code — but don't abstract prematurely
- Minimize dependencies — a little recode > a big dependency
- Design for testability — accept interfaces, inject dependencies, keep functions pure
Cross-References
- → See
samber/cc-skills-golang@golang-data-structuresskill for data structure selection, internals, and container/ packages - → See
samber/cc-skills-golang@golang-error-handlingskill for error wrapping, sentinel errors, and the single handling rule - → See
samber/cc-skills-golang@golang-structs-interfacesskill for interface design and composition - → See
samber/cc-skills-golang@golang-concurrencyskill for goroutine lifecycle and graceful shutdown - → See
samber/cc-skills-golang@golang-contextskill for timeout and cancellation patterns - → See
samber/cc-skills-golang@golang-project-layoutskill for architecture and directory structure
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

