go-repository-pattern
SKILL.md
When to Use
- Creating a new repository for a domain aggregate
- Implementing PostgreSQL adapter with sqlc
- Writing database migrations
- Setting up database connection and pooling
- Adding transactional support
- Creating in-memory repository for local dev / unit tests
Critical Patterns
| Pattern | Rule |
|---|---|
| Interface in domain | Repository interface lives in domain/port.go |
| sqlc for PostgreSQL | Write SQL, generate type-safe Go code — no ORMs, no manual scanning |
| In-memory for local/tests | Pure Go map implementation for zero-dep development |
| Migrations versioned | Use golang-migrate with sequential numbered files |
| Each service owns its DB | No shared databases between microservices |
| Context everywhere | All repository methods accept context.Context as first parameter |
| Domain ≠ DB model | sqlc generates DB structs; map them to domain entities in the adapter |
Architecture
internal/{domain}/
domain/
port.go # Repository interface (what the domain needs)
infrastructure/
repository/
query.sql # SQL queries with sqlc annotations
sqlc.yaml # sqlc configuration
db/ # Generated by sqlc — DO NOT EDIT
models.go # DB structs
query.sql.go # Type-safe query functions
db.go # DBTX interface
postgres.go # Adapter: implements domain port using sqlc
memory.go # In-memory implementation
Domain Port (Interface)
See assets/port.go
sqlc Setup
Configuration
See assets/sqlc.yaml
SQL Queries
See assets/query.sql
Generated Code (DO NOT EDIT)
sqlc generates:
PostgreSQL Adapter (uses sqlc)
In-Memory Implementation (Local + Unit Tests)
See assets/memory.go
When to Use Which Implementation
| Context | Implementation | Why |
|---|---|---|
| Unit tests | In-memory | Zero deps, instant, tests domain logic |
| Local dev without Docker | In-memory | No Postgres needed, fast startup |
| Local dev with Docker | PostgreSQL (sqlc) | Validate real SQL |
| Integration tests | PostgreSQL via testcontainers | Validate real SQL in CI |
| dev / staging / production | PostgreSQL (sqlc) | Real persistence |
Wiring by Environment
See assets/wiring.go
Database Connection (pgx pool)
Migrations
Use golang-migrate:
migrations/
000001_create_users.up.sql
000001_create_users.down.sql
Transactions with sqlc
Commands
# Install sqlc CLI
brew install sqlc
# Generate code from SQL
cd internal/{domain}/infrastructure/repository && sqlc generate
# Verify generated code
go build ./...
# Install pgx driver
go get github.com/jackc/pgx/v5
go get github.com/jackc/pgx/v5/pgxpool
# Install migrate CLI
brew install golang-migrate
# Create migration
migrate create -ext sql -dir migrations -seq create_users
# Run migrations
migrate -path migrations -database "postgres://user:pass@localhost:5432/dbname?sslmode=disable" up
# Rollback
migrate -path migrations -database "..." down 1
Makefile Targets
See assets/Makefile
Anti-Patterns
| Don't | Do |
|---|---|
Edit generated db/ files |
Edit query.sql and run sqlc generate |
| Import sqlc/pgx in domain | Domain defines interface, infra implements with sqlc |
| Use GORM or other ORMs | Use sqlc — you write SQL, it generates type-safe Go |
Use sqlx for new code |
Use sqlc + pgx — better type safety, less boilerplate |
| Shared database between services | Each service owns its schema |
Return pgx.ErrNoRows to application |
Map to domain error like ErrUserNotFound |
| Use sqlc structs as domain entities | Map sqlc structs to domain entities in the adapter |
| Skip in-memory implementation | Always provide in-memory for fast local dev + unit tests |
Weekly Installs
1
Repository
333-333-333/agentsFirst Seen
6 days ago
Security Audits
Installed on
amp1
cline1
opencode1
cursor1
kimi-cli1
kiro-cli1