Skip to content
Development
Skill

/golang-web

Modern Go Web application architecture guide. Use when creating new Go web projects, APIs, or microservices. Covers project structure, tech stack selection, and best practices based on Go standards.

From plugin
spellbook
25893 skills10 agents
Install
$ npx -y skills add majiayu000/spellbook --skill golang-web --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/golang-web

Context preview

The summary Claude sees to decide when to auto-load this skill.

Modern Go Web application architecture guide. Use when creating new Go web projects, APIs, or microservices. Covers project structure, tech stack selection, and best practices based on Go standards.

SKILL.md

golang-web.SKILL.md
name: golang-web
description: Modern Go Web application architecture guide. Use when creating new Go web projects, APIs, or microservices. Covers project structure, tech stack selection, and best practices based on Go standards.

Go Web Architecture

Core Principles

  • **Standard layout** — Follow cmd/internal/pkg convention
  • **Explicit dependencies** — Wire dependencies in main.go, no globals
  • **Interface-driven** — Define interfaces where you use them, not where you implement
  • **Error wrapping** — Wrap errors with context, use error codes
  • **No backwards compatibility** — Delete, don't deprecate. Change directly
  • **LiteLLM for LLM APIs** — Use LiteLLM proxy for all LLM integrations

---

No Backwards Compatibility

> **Delete unused code. Change directly. No compatibility layers.**

// ❌ BAD: Deprecated function kept around
// Deprecated: Use NewUserService instead
func CreateUserService() *UserService { ... }

// ❌ BAD: Alias for renamed types
type OldName = NewName // "for backwards compatibility"

// ❌ BAD: Unused parameters
func Process(_ context.Context, data Data) { ... }

// ✅ GOOD: Just delete and update all usages
func NewUserService(repo UserRepository) *UserService { ... }

---

LiteLLM for LLM APIs

> **Use LiteLLM proxy. Don't call provider APIs directly.**

// adapters/llm/client.go
package llm

import (
    "github.com/sashabaranov/go-openai"
)

// Connect to LiteLLM proxy using OpenAI-compatible SDK
func NewClient(cfg Config) *openai.Client {
    config := openai.DefaultConfig(cfg.APIKey)
    config.BaseURL = cfg.BaseURL // LiteLLM proxy URL
    return openai.NewClientWithConfig(config)
}

---

Quick Start

1. Initialize Project

mkdir myapp && cd myapp
go mod init github.com/yourname/myapp

# Install core dependencies
go get github.com/gin-gonic/gin
go get github.com/spf13/viper
go get github.com/sirupsen/logrus
go get gorm.io/gorm

2. Apply Tech Stack

| Layer | Recommendation | |-------|----------------| | HTTP Framework | Gin / Chi / Echo | | Configuration | Viper | | Logging | Logrus / Zap / Slog | | Database ORM | GORM / sqlx / sqlc | | Validation | go-playground/validator | | Testing | testify / go test |

Version Strategy

> **Always get latest. Never pin in templates.**

# Always fetch latest
go get -u github.com/gin-gonic/gin
go get -u ./...

# go.mod handles version locking
# go.sum ensures reproducible builds

3. Use Standard Structure

myapp/
├── cmd/
│   └── myapp/
│       └── main.go            # Entry point, dependency wiring
├── configs/
│   └── config.go              # Configuration struct + loader
├── internal/                  # Private application code
│   ├── handlers/              # HTTP handlers
│   ├── services/              # Business logic
│   ├── repositories/          # Data access
│   ├── models/                # Domain models
│   ├── middleware/            # HTTP middleware
│   └── router/                # Route definitions
├── pkg/                       # Public reusable packages
│   ├── errors/                # Error types
│   ├── logger/                # Logging setup
│   ├── response/              # Unified response format
│   └── database/              # Database connection
├── config.yaml                # Configuration file
├── Makefile                   # Build automation
├── Dockerfile
└── go.mod

---

Architecture Layers

cmd/ — Entry Point

Wire all dependencies here. No business logic.

// cmd/myapp/main.go
func main() {
    // Load config
    cfg := configs.Load()

    // Initialize infrastructure
    db := database.New(cfg.Database)
    cache := cache.New(cfg.Redis)
    logger := logger.New(cfg.Log)

    // Initialize repositories
    userRepo := repositories.NewUserRepository(db)

    // Initialize services
    userService := services.NewUserService(userRepo)

    // Initialize handlers
    userHandler := handlers.NewUserHandler(userService)

    // Setup router
    r := router.Setup(cfg, userHandler)

    // Start server with graceful shutdown
    server.Run(r, cfg.Server)
}

internal/ — Private Business Code

handlers/ — HTTP Layer

// internal/handlers/user.go
type UserHandler struct {
    service services.UserService
}

func NewUserHandler(s services.UserService) *UserHandler {
    return &UserHandler{service: s}
}

func (h *UserHandler) Create(c *gin.Context) {
    var input CreateUserInput
    if err := c.ShouldBindJSON(&input); err != nil {
        response.Error(c, errors.ErrInvalidParams)
        return
    }

    user, err := h.service.Create(c.Request.Context(), input)
    if err != nil {
        response.Error(c, err)
        return
    }

    response.Success(c, user)
}

services/ — Business Logic

// internal/services/user.go
type UserService interface {
    Create(ctx context.Context, input CreateUserInput) (*models.User, error)
    GetByID(ctx context.Context, id string) (*models.User, error)
}

type userService struct {
    repo repositories.UserRepository
}

func NewUserService(repo repositories.UserRepository) UserService {
    return &userService{repo: repo}
}

func (s *userService) Create(ctx context.Context, input CreateUserInput) (*models.User, error) {
    existing, _ := s.repo.FindByEmail(ctx, input.Email)
    if existing != nil {
        return nil, errors.ErrUserExists
    }

    user := &models.User{
        ID:    uuid.New().String(),
        Email: input.Email,
        Name:  input.Name,
    }

    return s.repo.Save(ctx, user)
}

repositories/ — Data Access

// internal/repositories/user.go
type UserRepository interface {
    FindByID(ctx context.Context, id string) (*models.User, error)
    FindByEmail(ctx context.Context, email string) (*models.User, error)
    Save(ctx context.Context, user *models.User) (*models.User, error)
    Delete(ctx context.Context, id string) error
}

type userRepository struct {
    db *gorm.DB
}

func NewUserRep
Read more
Ships withspellbook

Cross-runtime skills for Claude Code, Codex, and multi-agent workflows.

Get the whole plugin

Other skills on spellbook.