go
Write reliable, efficient Go code following idiomatic patterns and best practices. Use when building Go applications, implementing error handling with error wrapping, writing concurrent code with goro
SKILL.md.claude/skills/go/SKILL.md
GitHubGo Development
Purpose: Best practices for Go development including project structure, concurrency, error handling, and testing.
When to Use This Skill
- Building Go applications and microservices
- Implementing error handling with wrapping and sentinel errors
- Writing concurrent code with goroutines and channels
- Designing Go interfaces for testability
- Structuring Go project layouts
Prerequisites
- Go 1.21+ installed
- Go modules enabled
Table of Contents
- Project Structure
- Code Style
- Error Handling
- Concurrency
- Testing
- Interfaces
- Performance
- Security
- Best Practices
Project Structure
Standard Layout
project/
+-- cmd/
| -- myapp/
| -- main.go # Application entry point
+-- internal/
| +-- config/ # Configuration handling
| +-- handlers/ # HTTP handlers
| +-- models/ # Domain models
| +-- repository/ # Data access
| -- service/ # Business logic
+-- pkg/
| -- utils/ # Reusable packages
+-- api/
| -- openapi.yaml # API specification
+-- configs/
| -- config.yaml # Configuration files
+-- scripts/
| -- setup.sh # Build/deploy scripts
+-- go.mod
+-- go.sum
-- README.md
Package Naming
// Package names should be lowercase, short, and descriptive
package user // Good
package userService // Bad - no camelCase
package user_svc // Bad - no underscores
// Import path should match directory structure
import "myapp/internal/service"
Code Style
Naming Conventions
// Exported names start with uppercase
type UserService struct {}
func GetUser(id string) {}
// Unexported names start with lowercase
type userRepository struct {}
func validateEmail(email string) bool {}
// Use MixedCaps, not underscores
var maxRetryCount = 3 // Good
var max_retry_count = 3 // Bad
// Acronyms should be all caps or all lowercase
var userID string // Good
var userId string // Bad
type HTTPClient struct {} // Good
type HttpClient struct {} // Bad
Formatting
// Always use gofmt or goimports
// go fmt ./...
// Group imports: std lib, external, internal
import (
"context"
"fmt"
"net/http"
"github.com/gorilla/mux"
"go.uber.org/zap"
"myapp/internal/config"
"myapp/internal/service"
)
Comments
// Package level comment (required for exported packages)
// Package user provides user management functionality.
package user
// Exported function comment (required)
// GetByID retrieves a user by their unique identifier.
// It returns ErrNotFound if the user doesn't exist.
func GetByID(ctx context.Context, id string) (*User, error) {
// Implementation
}
// Don't comment obvious code
x++ // increment x - BAD
Best Practices
[PASS] DO
- Use
gofmtandgolint - Handle all errors
- Use context for cancellation
- Write table-driven tests
- Keep interfaces small
- Document exported functions
- Use meaningful variable names
[FAIL] DON'T
- Ignore errors
- Use global variables for state
- Use
init()functions unnecessarily - Create huge interfaces
- Use naked returns in long functions
- Use
panicfor normal errors - Premature optimization
References
Version: 1.0 Last Updated: February 5, 2026
Troubleshooting
| Issue | Solution |
|---|---|
| Goroutine leak | Use context.Context for cancellation, ensure goroutines have exit conditions |
| Race condition detected | Run go test -race, use mutexes or channels for shared state |
| Import cycle | Extract shared types into a separate package, use interfaces to break dependencies |