Project Structure¶
HexaGo generates a well-organized directory structure that enforces hexagonal architecture boundaries.
Default Structure¶
my-app/
├── cmd/ # CLI commands (Cobra)
│ ├── root.go # Root command + Viper configuration
│ └── run.go # Server startup with graceful shutdown
│
├── internal/ # Private application code
│ ├── core/ # 🎯 CORE — No external dependencies
│ │ ├── domain/ # Business entities and value objects
│ │ │ └── .gitkeep
│ │ └── services/ # Business logic and use cases
│ │ └── .gitkeep
│ │
│ ├── adapters/ # 🔌 ADAPTERS — External interfaces
│ │ ├── primary/ # Inbound (drives the application)
│ │ │ └── http/ # HTTP handlers
│ │ │ └── .gitkeep
│ │ └── secondary/ # Outbound (driven by the application)
│ │ └── database/ # Database repositories
│ │ └── .gitkeep
│ │
│ ├── config/ # Configuration management
│ │ └── config.go # Viper config struct and loader
│ │
│ └── observability/ # (with --with-observability)
│ ├── health.go # Health check endpoints
│ └── metrics.go # Prometheus metrics
│
├── pkg/ # Reusable packages (safe to import by others)
│ └── logger/
│ └── logger.go # Structured logger interface + implementation
│
├── migrations/ # (with --with-migrations)
│ └── .gitkeep
│
├── main.go # Minimal entry point — calls cmd.Execute()
├── Makefile # Build, test, lint, docker targets
├── Dockerfile # (with --with-docker) Multi-stage build
├── compose.yaml # (with --with-docker) Docker Compose services
├── .gitignore
└── README.md # Architecture documentation for the project
Key Directories Explained¶
cmd/¶
Contains Cobra commands:
root.go— Initializes Viper configuration, reads.my-app.yamland environment variablesrun.go— Starts the HTTP server with context-based graceful shutdown. Listens for SIGINT/SIGTERM.
internal/core/¶
The innermost layer — zero external dependencies allowed.
| Directory | Contents |
|---|---|
domain/ |
Entities (User, Order), value objects (Email, Money), domain errors |
services/ |
Use cases (CreateUser, ProcessOrder), port interface definitions |
internal/adapters/¶
Connects the core to the outside world.
| Directory | Contents |
|---|---|
primary/http/ |
HTTP handlers (framework-specific) |
primary/grpc/ |
gRPC handlers |
primary/queue/ |
Message queue consumers |
secondary/database/ |
Database repositories |
secondary/external/ |
External API clients |
secondary/cache/ |
Cache adapters |
pkg/¶
Reusable packages that are safe to import by external projects. Currently contains the logger.
migrations/¶
SQL migration files (when --with-migrations is used). Files follow the golang-migrate naming convention:
000001_create_users_table.up.sql
000001_create_users_table.down.sql
000002_add_email_index.up.sql
000002_add_email_index.down.sql
DDD / Driver-Driven Naming Variant¶
When using --adapter-style driver-driven --core-logic usecases --explicit-ports:
my-app/
├── internal/
│ ├── core/
│ │ ├── domain/
│ │ ├── usecases/ # (instead of services/)
│ │ └── ports/ # (with --explicit-ports) Interface definitions
│ └── adapters/
│ ├── driver/ # (instead of primary/)
│ └── driven/ # (instead of secondary/)
After Adding Components¶
Running hexago add commands populates the structure:
my-app/
├── internal/
│ ├── core/
│ │ ├── domain/
│ │ │ ├── user.go # hexago add domain entity User
│ │ │ ├── user_test.go
│ │ │ ├── email.go # hexago add domain valueobject Email
│ │ │ └── email_test.go
│ │ └── services/
│ │ ├── create_user.go # hexago add service CreateUser
│ │ └── create_user_test.go
│ └── adapters/
│ ├── primary/http/
│ │ └── user_handler.go # hexago add adapter primary http UserHandler
│ └── secondary/database/
│ └── user_repository.go # hexago add adapter secondary database UserRepository
└── migrations/
├── 000001_create_users.up.sql # hexago add migration create_users
└── 000001_create_users.down.sql
Configuration File¶
The generated project reads configuration from .my-app.yaml (where my-app is your project name):
server:
port: 8080
readtimeout: 15s
writetimeout: 15s
shutdowntimeout: 30s
loglevel: info # debug, info, warn, error
logformat: json # json, text
All config values can be overridden with environment variables using the MY_APP_ prefix: