Hexagonal Architecture
Hexagonal architecture relies on DI to wire ports to their adapters at the composition root. Hexagonal Architecture
Dependency injection (DI) is the practice of providing a component with its dependencies rather than having the component create them. Instead of a service instantiating its database connection, logger, and HTTP client internally, those dependencies are passed in — as constructor parameters, function arguments, or struct fields.
The concept follows directly from the Dependency Inversion Principle (the D in SOLID): high-level modules should not depend on low-level modules; both should depend on abstractions. In practice, this means a PaymentService should depend on a PaymentGateway interface, not on a concrete StripeClient. Whatever implements PaymentGateway — Stripe, a mock, a test double — is injected at the point where the service is created.
Dependency injection is not a framework feature. It’s a coding discipline. In Go, it’s often done manually through constructors. Frameworks like wire (Google) or fx (Uber) automate the wiring for large applications, but the principle is the same: dependencies flow in from the outside, not up from within.
// BAD — dependency created internallytype OrderService struct{}
func (s *OrderService) PlaceOrder(ctx context.Context, cmd PlaceOrderCommand) error { db, _ := pgx.Connect(ctx, os.Getenv("DATABASE_URL")) // created internally // ...}
// GOOD — dependency injectedtype OrderService struct { repo OrderRepository // interface, not concrete events EventPublisher}
func NewOrderService(repo OrderRepository, events EventPublisher) *OrderService { return &OrderService{repo: repo, events: events}}The constructor makes dependencies explicit, visible, and swappable.
Manual DI through constructors is idiomatic Go. For large services with many components, a composition root pattern centralizes all wiring:
func Run(version string) error { cfg := config.Load()
db, err := postgres.NewConnection(cfg.Database) if err != nil { return fmt.Errorf("database: %w", err) }
repo := postgres.NewOrderRepository(db) events := eventbus.New() svc := order.NewOrderService(repo, events) handler := httphandler.NewOrderHandler(svc)
// wire everything into the HTTP server}The entire dependency graph is constructed in one place. This is the bootstrap pattern verikt scaffolds.
The bootstrap capability generates a thin main.go and internal/bootstrap/bootstrap.go where all dependency wiring lives. Each capability adds its initialization code to this composition root via partial injection. See How It Works for how partials are injected.
Hexagonal Architecture
Hexagonal architecture relies on DI to wire ports to their adapters at the composition root. Hexagonal Architecture
Repository Pattern
Repositories are injected into services as interfaces — a canonical DI use case. Repository Pattern
How It Works
How verikt’s bootstrap pattern and partial injection implement DI automatically. How It Works