go-best-practices
Provides Go patterns for type-first development with custom types, interfaces, functional options, and error handling. Must use when reading or writing Go files.
Best use case
go-best-practices is best used when you need a repeatable AI agent workflow instead of a one-off prompt. It is especially useful for teams working in multi. Provides Go patterns for type-first development with custom types, interfaces, functional options, and error handling. Must use when reading or writing Go files.
Provides Go patterns for type-first development with custom types, interfaces, functional options, and error handling. Must use when reading or writing Go files.
Users should expect a more consistent workflow output, faster repeated execution, and less time spent rewriting prompts from scratch.
Practical example
Example input
Use the "go-best-practices" skill to help with this workflow task. Context: Provides Go patterns for type-first development with custom types, interfaces, functional options, and error handling. Must use when reading or writing Go files.
Example output
A structured workflow result with clearer steps, more consistent formatting, and an output that is easier to reuse in the next run.
When to use this skill
- Use this skill when you want a reusable workflow rather than writing the same prompt again and again.
When not to use this skill
- Do not use this when you only need a one-off answer and do not need a reusable workflow.
- Do not use it if you cannot install or maintain the related files, repository context, or supporting tools.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/go-best-practices/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How go-best-practices Compares
| Feature / Agent | go-best-practices | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Provides Go patterns for type-first development with custom types, interfaces, functional options, and error handling. Must use when reading or writing Go files.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Go Best Practices
## Type-First Development
Types define the contract before implementation. Follow this workflow:
1. **Define data structures** - structs and interfaces first
2. **Define function signatures** - parameters, return types, and error conditions
3. **Implement to satisfy types** - let the compiler guide completeness
4. **Validate at boundaries** - check inputs where data enters the system
### Make Illegal States Unrepresentable
Use Go's type system to prevent invalid states at compile time.
**Structs for domain models:**
```go
// Define the data model first
type User struct {
ID UserID
Email string
Name string
CreatedAt time.Time
}
type CreateUserRequest struct {
Email string
Name string
}
// Functions follow from the types
func CreateUser(req CreateUserRequest) (*User, error) {
// implementation
}
```
**Custom types for domain primitives:**
```go
// Distinct types prevent mixing up IDs
type UserID string
type OrderID string
func GetUser(id UserID) (*User, error) {
// Compiler prevents passing OrderID here
}
func NewUserID(raw string) UserID {
return UserID(raw)
}
// Methods attach behavior to the type
func (id UserID) String() string {
return string(id)
}
```
**Interfaces for behavior contracts:**
```go
// Define what you need, not what you have
type Reader interface {
Read(p []byte) (n int, err error)
}
type UserRepository interface {
GetByID(ctx context.Context, id UserID) (*User, error)
Save(ctx context.Context, user *User) error
}
// Accept interfaces, return structs
func ProcessInput(r Reader) ([]byte, error) {
return io.ReadAll(r)
}
```
**Enums with iota:**
```go
type Status int
const (
StatusActive Status = iota + 1
StatusInactive
StatusPending
)
func (s Status) String() string {
switch s {
case StatusActive:
return "active"
case StatusInactive:
return "inactive"
case StatusPending:
return "pending"
default:
return fmt.Sprintf("Status(%d)", s)
}
}
// Exhaustive handling in switch
func ProcessStatus(s Status) (string, error) {
switch s {
case StatusActive:
return "processing", nil
case StatusInactive:
return "skipped", nil
case StatusPending:
return "waiting", nil
default:
return "", fmt.Errorf("unhandled status: %v", s)
}
}
```
**Functional options for flexible construction:**
```go
type ServerOption func(*Server)
func WithPort(port int) ServerOption {
return func(s *Server) {
s.port = port
}
}
func WithTimeout(d time.Duration) ServerOption {
return func(s *Server) {
s.timeout = d
}
}
func NewServer(opts ...ServerOption) *Server {
s := &Server{
port: 8080, // sensible defaults
timeout: 30 * time.Second,
}
for _, opt := range opts {
opt(s)
}
return s
}
// Usage: NewServer(WithPort(3000), WithTimeout(time.Minute))
```
**Embed for composition:**
```go
type Timestamps struct {
CreatedAt time.Time
UpdatedAt time.Time
}
type User struct {
Timestamps // embedded - User has CreatedAt, UpdatedAt
ID UserID
Email string
}
```
## Module Structure
Prefer smaller files within packages: one type or concern per file. Split when a file handles multiple unrelated types or exceeds ~300 lines. Keep tests in `_test.go` files alongside implementation. Package boundaries define the API; internal organization is flexible.
## Functional Patterns
- Use value receivers when methods don't mutate state; reserve pointer receivers for mutation.
- Avoid package-level mutable variables; pass dependencies explicitly via function parameters.
- Return new structs/slices rather than mutating inputs; makes data flow explicit.
- Use closures and higher-order functions where they simplify code (e.g., `sort.Slice`, iterators).
## Instructions
- Return errors with context using `fmt.Errorf` and `%w` for wrapping. This preserves the error chain for debugging.
- Every function returns a value or an error; unimplemented paths return descriptive errors. Explicit failures are debuggable.
- Handle all branches in `switch` statements; include a `default` case that returns an error. Exhaustive handling prevents silent bugs.
- Pass `context.Context` to external calls with explicit timeouts. Runaway requests cause cascading failures.
- Reserve `panic` for truly unrecoverable situations; prefer returning errors. Panics crash the program.
- Add or update table-driven tests for new logic; cover edge cases (empty input, nil, boundaries).
## Examples
Explicit failure for unimplemented logic:
```go
func buildWidget(widgetType string) (*Widget, error) {
return nil, fmt.Errorf("buildWidget not implemented for type: %s", widgetType)
}
```
Wrap errors with context to preserve the chain:
```go
out, err := client.Do(ctx, req)
if err != nil {
return nil, fmt.Errorf("fetch widget failed: %w", err)
}
return out, nil
```
Exhaustive switch with default error:
```go
func processStatus(status string) (string, error) {
switch status {
case "active":
return "processing", nil
case "inactive":
return "skipped", nil
default:
return "", fmt.Errorf("unhandled status: %s", status)
}
}
```
Structured logging with slog:
```go
import "log/slog"
var log = slog.With("component", "widgets")
func createWidget(name string) (*Widget, error) {
log.Debug("creating widget", "name", name)
widget := &Widget{Name: name}
log.Debug("created widget", "id", widget.ID)
return widget, nil
}
```
## Configuration
- Load config from environment variables at startup; validate required values before use. Missing config should cause immediate exit.
- Define a Config struct as single source of truth; avoid `os.Getenv` scattered throughout code.
- Use sensible defaults for development; require explicit values for production secrets.
### Examples
Typed config struct:
```go
type Config struct {
Port int
DatabaseURL string
APIKey string
Env string
}
func LoadConfig() (*Config, error) {
dbURL := os.Getenv("DATABASE_URL")
if dbURL == "" {
return nil, fmt.Errorf("DATABASE_URL is required")
}
apiKey := os.Getenv("API_KEY")
if apiKey == "" {
return nil, fmt.Errorf("API_KEY is required")
}
port := 3000
if p := os.Getenv("PORT"); p != "" {
var err error
port, err = strconv.Atoi(p)
if err != nil {
return nil, fmt.Errorf("invalid PORT: %w", err)
}
}
return &Config{
Port: port,
DatabaseURL: dbURL,
APIKey: apiKey,
Env: getEnvOrDefault("ENV", "development"),
}, nil
}
```Related Skills
vue-pinia-best-practices
Pinia stores, state management patterns, store setup, and reactivity with stores.
vue-options-api-best-practices
Vue 3 Options API style (data(), methods, this context). Each reference shows Options API solution only.
next-best-practices
Next.js best practices - file conventions, RSC boundaries, data patterns, async APIs, metadata, error handling, route handlers, image/font optimization, bundling
security-best-practices
Implement security best practices for web applications and infrastructure. Use when securing APIs, preventing common vulnerabilities, or implementing security policies. Handles HTTPS, CORS, XSS, SQL Injection, CSRF, rate limiting, and OWASP Top 10.
supabase-postgres-best-practices
Postgres performance optimization and best practices from Supabase. Use this skill when writing, reviewing, or optimizing Postgres queries, schema designs, or database configurations.
postgres-best-practices
Postgres performance optimization and best practices from Supabase. Use this skill when writing, reviewing, or optimizing Postgres queries, schema designs, or database configurations.
nodejs-best-practices
Node.js development principles and decision-making. Framework selection, async patterns, security, and architecture. Teaches thinking, not copying.
nextjs-best-practices
Next.js App Router principles. Server Components, data fetching, routing patterns.
cloudformation-best-practices
CloudFormation template optimization, nested stacks, drift detection, and production-ready patterns. Use when writing or reviewing CF templates.
aws-iam-best-practices
IAM policy review, hardening, and least privilege implementation
api-security-best-practices
Implement secure API design patterns including authentication, authorization, input validation, rate limiting, and protection against common API vulnerabilities
angular-best-practices
Angular performance optimization and best practices guide. Use when writing, reviewing, or refactoring Angular code for optimal performance, bundle size, and rendering efficiency.