Go Project Structure Reference
go-projects.md
Go Project Structure Reference
Core Pattern (One Structure to Rule Them All)
myapp/
├── cmd/
│ └── {appname}/
│ └── main.go # Entry point, minimal logic
├── internal/ # Private application code
│ ├── domain/ # Business entities & interfaces
│ │ ├── user.go # type User struct
│ │ ├── errors.go # Domain-specific errors
│ │ └── interfaces.go # Repository interfaces
│ ├── service/ # Business logic
│ │ ├── user.go # UserService
│ │ └── aggregate.go # Multi-entity operations
│ ├── storage/ # Repository implementations
│ │ ├── postgres/
│ │ ├── memory/
│ │ └── cache/
│ └── transport/ # API layer
│ ├── http/
│ │ ├── handler.go
│ │ ├── middleware.go
│ │ └── routes.go
│ └── grpc/
│ └── server.go
├── pkg/ # Public packages (importable)
│ ├── errors/
│ └── types/
├── migrations/ # Database migrations
│ └── 001_initial.sql
├── config/ # Configuration files
├── go.mod
├── go.sum
├── Makefile
└── README.md
Package Responsibilities
/cmd
- Entry points only
- Parse flags/env
- Initialize dependencies
- Start servers
/internal/domain
go
// Business entities
type User struct {
ID string
Email string
}
// Repository interfaces (ports)
type UserRepository interface {
Get(ctx context.Context, id string) (*User, error)
Save(ctx context.Context, user *User) error
}
/internal/service
go
// Business logic
type UserService struct {
repo UserRepository
}
func (s UserService) CreateUser(ctx context.Context, email string) (User, error) {
// Business rules here
}
/internal/storage
go
// Repository implementations (adapters)
type PostgresUserRepo struct {
db *sql.DB
}
func (r PostgresUserRepo) Get(ctx context.Context, id string) (User, error) {
// SQL implementation
}
/internal/transport
go
// HTTP handlers
func (h Handler) CreateUser(w http.ResponseWriter, r http.Request) {
// HTTP concerns only
// Call service layer
}
Scaling Patterns
Single Module → Multiple Modules
internal/
├── auth/ # Module 1
│ ├── domain/
│ ├── service/
│ ├── storage/
│ └── transport/
├── billing/ # Module 2
│ ├── domain/
│ ├── service/
│ ├── storage/
│ └── transport/
└── shared/ # Cross-module
├── middleware/
└── database/
CLI Applications
mycli/
├── cmd/
│ ├── root.go # Command setup
│ ├── init.go # subcommand: mycli init
│ └── sync.go # subcommand: mycli sync
├── internal/
│ └── core/ # Business logic
├── main.go # Entry point
└── go.mod
Key Principles
1. Dependency Rule
transport → service → domain ← storage
↖__↗
2. Interface Ownership
3. Error Handling
go
// Domain errors
var ErrUserNotFound = errors.New("user not found")
// Wrap with context
return fmt.Errorf("get user: %w", ErrUserNotFound)
4. Configuration
go
type Config struct {
Port string env:"PORT" default:"8080"
Database string env:"DATABASE_URL" required:"true"
}
Common Patterns
Repository Pattern
go
type Repository[T any] interface {
Get(ctx context.Context, id string) (T, error)
List(ctx context.Context, filter Filter) ([]T, error)
Save(ctx context.Context, entity T) error
Delete(ctx context.Context, id string) error
}
Service Aggregates
go
type UserGroupAggregate struct {
users Repository[*User]
groups Repository[*Group]
members Repository[*Member]
}
Middleware Chain
go
type MiddlewareFunc func(http.Handler) http.Handler
handler = middleware.Chain(
middleware.Logger,
middleware.Auth,
middleware.RateLimit,
)(handler)
File Naming Conventions
user.go
- Domain entityuser_service.go
- Service layeruser_handler.go
- HTTP handlersuser_test.go
- Testsinterfaces.go
- Shared interfaceserrors.go
- Error definitionsTesting Structure
internal/service/
├── user.go
├── user_test.go # Unit tests
└── userintegrationtest.go # Integration tests
When to Add Structure
Quick Start Commands
bash
Initialize module
go mod init github.com/user/myapp
Create structure
mkdir -p cmd/api internal/{domain,service,storage,transport/http}
Run
go run cmd/api/main.go
Test
go test ./...
Build
go build -o bin/api cmd/api/main.go
Anti-Patterns to Avoid
❌ Deep nesting: internal/app/services/user/handlers/http/v1/
❌ Circular dependencies between packages
❌ Business logic in handlers or repositories
❌ Shared mutable state
❌ God structs with too many dependencies
Remember
Based on DDD principles and modern Go practices. One structure that scales from prototype to production.