Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
samber avatar

Golang Design Patterns

  • 35.1k installs
  • 2.8k repo stars
  • Updated July 27, 2026
  • samber/cc-skills-golang

golang-design-patterns is a Claude Code skill that gets coding agents to output idiomatic, production-grade Go constructor patterns and architecture decisions.

About

golang-design-patterns is an agent skill that makes coding agents output idiomatic, production-grade Go constructor patterns and architecture decisions. It codifies functional options over builders, avoiding init(), early error returns, per-call timeouts, bounded resources, graceful shutdown, and dependency injection, with reference guides on clean, hexagonal, and DDD architectures. A developer uses it in design mode when creating new Go APIs or in review mode when auditing existing Go code for design issues.

  • Idiomatic Go constructor patterns (functional options over builder)
  • Resource lifecycle, timeouts, graceful shutdown, and DI
  • Design and review modes with clean/hexagonal/DDD references

Golang Design Patterns by the numbers

  • 35,079 all-time installs (skills.sh)
  • +628 installs in the week ending Jul 28, 2026 (Skillselion tracking)
  • Ranked #1 of 99 Go skills by installs in the Skillselion catalog
  • Security screen: LOW risk (skills.sh audit)
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
At a glance

golang-design-patterns capabilities & compatibility

Free, no API key; requires the go toolchain

Capabilities
go design patterns · constructor design · dependency injection · graceful shutdown · architecture review
Use cases
refactoring · code review · api development
Pricing
Free
From the docs

What golang-design-patterns says it does

Constructors SHOULD use **functional options** — they scale better as APIs evolve (one function per option, no breaking changes)
SKILL.md
Idiomatic Go patterns for production-ready code.
SKILL.md
**Avoid `init()`** — runs implicitly, cannot return errors, makes testing unpredictable. Use explicit constructors
SKILL.md
npx skills add https://github.com/samber/cc-skills-golang --skill golang-design-patterns

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs35.1k
repo stars2.8k
Security audit3 / 3 scanners passed
Last updatedJuly 27, 2026
Repositorysamber/cc-skills-golang

Which idiomatic Go pattern fits this constructor, resource, or architecture decision?

refactoring

Who is it for?

Go developers choosing architectural patterns or designing constructor APIs who want idiomatic, explicit code over anti-patterns.

Skip if: Error-handling, context propagation, or struct/interface design, which are split into separate golang skills.

When should I use this skill?

When choosing between architectural patterns, implementing functional options, designing constructor APIs, setting up graceful shutdown, or applying resilience patterns.

What you get

Go code that uses functional options, early error returns, bounded resources, per-call timeouts, and injected dependencies.

  • Idiomatic Go constructors and API design
  • Design-issue review findings

By the numbers

  • 21-item best-practices summary
  • 5 architecture reference guides (clean, hexagonal, DDD, data-handling, resource-management)

Files

SKILL.mdMarkdownGitHub ↗

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-patterns skill 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

1. Constructors SHOULD use functional options — they scale better as APIs evolve (one function per option, no breaking changes) 2. Functional options MUST return an error if validation can fail — catch bad config at construction, not at runtime 3. Avoid `init()` — runs implicitly, cannot return errors, makes testing unpredictable. Use explicit constructors 4. Enums SHOULD start at 1 (or Unknown sentinel at 0) — Go's zero value silently passes as the first enum member 5. Error cases MUST be handled first with early return — keep happy path flat 6. Panic is for bugs, not expected errors — callers can handle returned errors; panics crash the process 7. `defer Close()` immediately after opening — later code changes can accidentally skip cleanup 8. `runtime.AddCleanup` over runtime.SetFinalizer — finalizers are unpredictable and can resurrect objects 9. Every external call SHOULD have a timeout — a slow upstream hangs your goroutine indefinitely 10. Limit everything (pool sizes, queue depths, buffers) — unbounded resources grow until they crash 11. Retry logic MUST check context cancellation between attempts 12. Use `strings.Builder` for concatenation in loops → see samber/cc-skills-golang@golang-code-style 13. string vs []byte: use `[]byte` for mutation and I/O, string for display and keys — conversions allocate 14. Iterators (Go 1.23+): use for lazy evaluation — avoid loading everything into memory 15. Stream large transfers — loading millions of rows causes OOM; stream keeps memory constant 16. //go:embed for static assets — embeds at compile time, eliminates runtime file I/O errors 17. Use `crypto/rand` for keys/tokens — math/rand is predictable → see samber/cc-skills-golang@golang-security 18. Regexp MUST be compiled once at package level — compilation is O(n) and allocates 19. Compile-time interface checks: *`var _ Interface = (Type)(nil)` 20. A little recode > a big dependency — each dep adds attack surface and maintenance burden 21. 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 string

Compile-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 use defer f.Close(), but write/flush resources must report close or flush errors when durability matters

Data Handling

string vs []byte vs []rune

TypeDefault forUse when
stringEverythingImmutable, safe, UTF-8
[]byteI/OWriting to io.Writer, building strings, mutations
[]runeUnicode opslen() 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

GuideScope
Architecture PatternsHigh-level principles, when each architecture fits
Clean ArchitectureUse cases, dependency rule, layered adapters
Hexagonal ArchitecturePorts and adapters, domain core isolation
Domain-Driven DesignAggregates, 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-structures skill for data structure selection, internals, and container/ packages
  • → See samber/cc-skills-golang@golang-error-handling skill for error wrapping, sentinel errors, and the single handling rule
  • → See samber/cc-skills-golang@golang-structs-interfaces skill for interface design and composition
  • → See samber/cc-skills-golang@golang-concurrency skill for goroutine lifecycle and graceful shutdown
  • → See samber/cc-skills-golang@golang-context skill for timeout and cancellation patterns
  • → See samber/cc-skills-golang@golang-project-layout skill for architecture and directory structure

Related skills

How it compares

Pick golang-design-patterns over golang-code-style when the task is API constructor architecture rather than var versus := initialization style.

FAQ

What constructor pattern does it recommend?

Functional options over the builder pattern, because they scale as APIs evolve with one function per option and no breaking changes; options must return an error when validation can fail.

What modes does it run in?

Design mode for creating new APIs or structure, and review mode for auditing existing code for init() abuse, unbounded resources, and missing timeouts.

Is Golang Design Patterns safe to install?

skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.

Gobackend

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.