Claude Code for Go (Golang) — Complete Setup Guide
Claude Code works well with Go projects when configured to understand your module structure, error conventions, and test patterns. This guide covers the CLAUDE.md template, automated go test hooks, idiomatic Go configuration, and workflow patterns for HTTP services, CLI tools, and microservices.
Go CLAUDE.md Template
# Project: [Your Service Name]
## Stack
- Go 1.22
- Module: github.com/yourorg/yourservice (from go.mod)
- HTTP: net/http + chi router (or gin, echo, stdlib — specify yours)
- Database: pgx/v5 + sqlc (or database/sql, gorm — specify)
- Testing: go test, testify/assert, gomock
## Commands
```bash
go build ./... # build check
go test ./... # run all tests
go test ./... -race # race detector
go test ./internal/... -v # verbose test output
go test -run TestUserService # single test
golangci-lint run # lint
go vet ./... # vet
```
## Conventions
- Error wrapping: fmt.Errorf("functionName: %w", err)
- Context is always the first parameter for I/O functions
- Interfaces defined at call site, not definition package
- Table-driven tests using []struct{name, input, want, wantErr}
- No global state; pass dependencies via constructor or function params
- Avoid init() functions
## Project structure
- cmd/[service]/main.go — entry point
- internal/ — private packages
- handler/ — HTTP handlers
- service/ — business logic
- store/ — database layer
- model/ — shared types
- pkg/ — public/shared packages
Automated go test Hooks
Run tests after every edit so Claude sees failures immediately and fixes them in the same turn:
// .claude/settings.json
{
"allowedTools": ["Edit", "Write", "Bash", "Read", "Glob", "Grep"],
"hooks": [
{
"event": "PostToolUse",
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "cd $PROJECT_ROOT && go test ./... -count=1 2>&1 | tail -25"
}]
}
]
}
Use
-count=1 to disable Go's test result cache. Without it, Claude may see a cached pass and miss a newly introduced regression.Race detector hook (for concurrent code)
{
"event": "PostToolUse",
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "cd $PROJECT_ROOT && go test ./... -race -count=1 2>&1 | tail -30"
}]
}
Lint hook (golangci-lint)
{
"event": "PostToolUse",
"matcher": "Write",
"hooks": [{
"type": "command",
"command": "cd $PROJECT_ROOT && golangci-lint run --fast 2>&1 | head -20"
}]
}
Teaching Claude Idiomatic Go
By default Claude writes correct Go but may default to verbose patterns. Add these to CLAUDE.md:
| Pattern | CLAUDE.md instruction |
|---|---|
| Error wrapping | "Wrap errors: fmt.Errorf("methodName: %w", err)" |
| Context propagation | "ctx is always the first param for any function with I/O" |
| Interfaces | "Define interfaces at call site, in the consumer package" |
| Constructors | "Use NewFoo(deps...) *Foo pattern, no init()" |
| Table tests | "Use table-driven tests: tests := []struct{name, input, want}{}" |
| Goroutine safety | "Use errgroup for concurrent tasks; always propagate context cancellation" |
HTTP Service Workflows
Add a new endpoint
claude "add a PATCH /users/{id}/status endpoint.
Handler in internal/handler/user.go.
Service method in internal/service/user.go.
Store query in internal/store/user.go using sqlc.
Write table-driven tests for each layer.
Run go test ./... to verify."
Add middleware
claude "add rate-limiting middleware using golang.org/x/time/rate.
Limit: 100 req/min per IP. Return 429 with Retry-After header.
Wire it into cmd/api/main.go before the router.
Add integration test using httptest."
Database migration + model
claude "add a 'tags' column (text[], nullable) to the posts table.
Create a Goose migration file in migrations/.
Update the sqlc query file for posts.
Regenerate sqlc (sqlc generate).
Update the Post model and any handlers that return posts."
Concurrency Patterns
Concurrent fetch with errgroup
claude "rewrite FetchUserDashboard to fetch user, posts, and followers
concurrently using errgroup. Cancel all goroutines if any fails.
Propagate ctx. The function signature should stay the same."
Worker pool
claude "implement a worker pool for processing email jobs.
Pool size configurable via constructor. Use a buffered channel for the queue.
Graceful shutdown: drain queue on context cancel. Add tests with race detector."
CLI Tool Workflows (cobra/urfave)
# CLAUDE.md additions for CLI tools
## CLI Framework
- cobra v1.8 (cmd/ directory structure)
- Each subcommand in cmd/[subcommand].go
- Config via viper (config.yaml or env vars)
- Output: text to stdout, errors to stderr
## Commands
go run . [subcommand] [flags] # test locally
go build -o ./bin/[name] . # build binary
claude "add a 'sync' subcommand to the CLI. Usage: tool sync --source=dir --dest=bucket.
Use cobra for flag parsing. Progress bar with github.com/schollz/progressbar.
Dry-run flag --dry-run that prints what would be uploaded without uploading.
Write a unit test for the file collection logic."
5 Tips for Go + Claude Code
- Add your
.golangci.ymlto the repo and reference it in CLAUDE.md. Claude will generate code that passes your specific linter configuration. - For generated code (sqlc, protobuf, mocks), tell Claude: "Never edit files in internal/store/generated/ — those are sqlc output." Claude will correctly regenerate via the tool command instead of editing directly.
- Use
go test -run TestXxx -vin your hook for focused TDD. Switch togo test ./...for final verification. - Tell Claude your Go version. Go 1.22 has range-over-integer, range-over-func, and enhanced http.ServeMux. Claude will use the right idioms for your version.
- For gRPC services, share your .proto files with Claude and tell it "generate handlers that match the proto service definition exactly". Claude reads protos fluently.