Skip to main content
Businessbdfinst

hexagonal-architecture

Design with ports and adapters to separate business logic from infrastructure. Use when designing a new service, reviewing structural compliance, or deciding how to introduce a new external dependency without coupling the domain.

Stars
190
Source
bdfinst/agentic-dev-team
Updated
2026-05-30
Slug
bdfinst--agentic-dev-team--hexagonal-architecture
View on GitHubRaw SKILL.md

// install — copy + paste into any project

mkdir -p .claude/skills && curl -fsSL https://raw.githubusercontent.com/bdfinst/agentic-dev-team/HEAD/plugins/agentic-dev-team/skills/hexagonal-architecture/SKILL.md -o .claude/skills/hexagonal-architecture.md

Drops the SKILL.md into .claude/skills/hexagonal-architecture.md. Works with Claude Code, Cursor, and any agent that loads SKILL.md files from .claude/skills/.

Hexagonal Architecture (Ports & Adapters)

Overview

Design systems with clear separation between business logic and infrastructure. The domain core has zero dependencies on outer layers; all external interactions flow through explicitly defined ports and adapters.

Core Concepts

Ports

  • Interfaces that express application intent independent of technology
  • Inbound ports (driving): define use cases the application exposes (e.g., CreateOrderUseCase)
  • Outbound ports (driven): define what the application needs from the outside world (e.g., OrderRepository, PaymentGateway)

Adapters

  • Concrete implementations that connect ports to external systems
  • Inbound adapters: REST controllers, CLI handlers, message consumers, GraphQL resolvers
  • Outbound adapters: database repositories, HTTP clients, message publishers, file storage

Dependency Rule

  • All dependencies point inward toward the domain core
  • Domain knows nothing about adapters, frameworks, or infrastructure
  • Adapters depend on ports, never the reverse

Project Structure

src/
├── domain/              # Pure business logic, no framework dependencies
│   ├── model/           # Entities, value objects, aggregates
│   ├── service/         # Domain services
│   └── event/           # Domain events
├── application/         # Use cases / application services
│   ├── port/
│   │   ├── inbound/     # Use case interfaces (driving ports)
│   │   └── outbound/    # Repository/gateway interfaces (driven ports)
│   └── service/         # Use case implementations
├── infrastructure/      # Framework and technology concerns
│   ├── config/          # Dependency injection, app configuration
│   └── persistence/     # Database migrations, ORM config
└── adapter/
    ├── inbound/         # Controllers, CLI, event consumers
    └── outbound/        # Repository impls, API clients, message publishers

Steps

1. Identify Boundaries

  • Enumerate all external dependencies (databases, APIs, message brokers, file systems)
  • Identify each as an inbound or outbound interaction

2. Define Ports

  • Create an inbound port interface for each use case the application exposes
  • Create an outbound port interface for each external dependency the application needs

3. Implement Adapters

  • Build an adapter for each port connecting to the concrete technology
  • Verify all dependencies point inward (adapters depend on ports, never the reverse)

4. Validate Structure

  • Confirm domain layer has zero imports from infrastructure or adapter layers
  • Confirm tests can substitute adapters without touching domain logic

Output

Report structural compliance as a list of violations (port without adapter, domain importing infrastructure, etc.) or confirm the structure passes all checks. Be concise — violations only; no narration for passing checks.

Constraints

  • Do not embed framework dependencies in the domain layer
  • Do not bypass ports with direct infrastructure access from application services

Guidelines

  • Every external dependency gets its own adapter behind a port
  • Test domain logic by substituting adapters (e.g., in-memory repository for unit tests)
  • Introduce a new port when a new category of external interaction appears
  • Reuse existing ports when the interaction pattern is the same
  • Keep the application layer thin: orchestrate domain objects, don't duplicate domain logic