# Symfony Hexagonal Architecture

> Symfony hexagonal architecture setup — project structure, module scaffolding, layer responsibilities, dependency rules. Triggers on: architecture, module, layer, hexagonal, scaffold, project structure, directory structure, new project, new module

- Skill: `aligundogdu/symfony-hexagonal-architecture` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add aligundogdu/symfony-hexagonal-architecture`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aligundogdu/symfony-hexagonal-architecture/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: aligundogdu (https://skillmd.com/u/aligundogdu)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/aligundogdu/symfony-hexagonal-architecture

---


# Symfony Hexagonal Architecture

You are an expert in Symfony hexagonal architecture (ports & adapters). Use this skill when users need to set up project structure, create new modules, or understand layer responsibilities.

## When to Activate

- User wants to create a new Symfony project with hexagonal architecture
- User asks about project structure or directory layout
- User wants to scaffold a new module/bounded context
- User asks about layer responsibilities or dependency rules
- User mentions "hexagonal", "ports and adapters", "clean architecture" in Symfony context

## Core Principles

### Layer Direction (STRICT)
```
Presentation → Application → Domain ← Infrastructure
```

Infrastructure depends on Domain (implements ports), but Domain NEVER depends on Infrastructure.

### Module Structure

Every module follows this structure under `src/`:

```
Domain/{Module}/
├── Entity/          # Aggregates and entities (pure PHP)
├── ValueObject/     # Immutable value objects
├── Event/           # Domain events (past-tense)
├── Exception/       # Domain-specific exceptions
└── Port/            # Interfaces for external dependencies

Application/{Module}/
├── Command/         # Write operations (final readonly)
├── Query/           # Read operations (final readonly)
├── DTO/             # Data transfer objects
└── EventHandler/    # Domain event handlers

Infrastructure/{Module}/
├── Persistence/     # Doctrine repositories, mappings
├── Messaging/       # Messenger handlers, transports
└── ExternalService/ # HTTP clients, third-party APIs

Presentation/{Module}/
├── API/             # REST controllers
├── CLI/             # Console commands
└── GraphQL/         # GraphQL resolvers/types
```

## Progressive Refactoring (Existing Projects)

When working on an existing project that doesn't follow hexagonal architecture:

### Step 1: Detect Current Structure
Before writing any code, check:
```
- Is src/ organized by layer (Domain/, Application/, etc.) or by traditional Symfony (Controller/, Entity/, Repository/)?
- Does the module the user is working on already follow hexagonal patterns?
- Are there Doctrine annotations directly on entities?
```

### Step 2: Ask the User
When the user requests a feature/change in a non-hexagonal module, ALWAYS ask:

> "Bu modül (`{Module}`) şu anda hexagonal yapıda değil. Şu seçeneklerden birini tercih edebilirsiniz:
> 1. **Önce refactor**: `{Module}` modülünü hexagonal mimariye taşıyıp, sonra yeni özelliği ekleyeyim
> 2. **Sadece yeni kodu hexagonal yap**: Mevcut koda dokunmadan, yeni eklenen kısımları hexagonal yapıda oluşturayım
> 3. **Mevcut yapıda devam et**: Bu sefer hexagonal yapıyı atlayalım
>
> Hangisini tercih edersiniz?"

### Step 3: Incremental Migration (if user chooses refactor)
Migrate one layer at a time, in this order:

1. **Domain first**: Extract entities to `Domain/{Module}/Entity/`, create value objects, define port interfaces
2. **Application second**: Create Commands/Queries/Handlers, move business logic out of controllers/services
3. **Infrastructure third**: Move Doctrine repositories to `Infrastructure/{Module}/Persistence/`, extract mappings
4. **Presentation last**: Thin out controllers, add `ApiResponseTrait`, apply `#[IsGranted]`

After each layer, verify the code still works before moving to the next.

### Key Principles
- **Never touch modules the user isn't working on** — only refactor what's in scope
- **One module at a time** — don't try to migrate the whole project
- **Keep the app working** — each step should be a working state
- **Respect user's pace** — some teams prefer gradual migration over months

## Scaffolding a New Module

When user asks to create a new module, generate ALL directories and base files:

1. Create directory structure (all 4 layers)
2. Create a sample port interface in `Domain/{Module}/Port/`
3. Create a sample repository adapter in `Infrastructure/{Module}/Persistence/`
4. Bind the port to adapter in `services.yaml`
5. Suggest initial entities, commands, and queries based on the module purpose

## Key Rules

1. **Domain purity**: No `use Symfony\...` or `use Doctrine\...` in any Domain file
2. **Port-first**: Define the interface before the implementation
3. **One module = one bounded context**: Modules communicate via events, not direct calls
4. **Namespace convention**: `App\Domain\{Module}\...`, `App\Application\{Module}\...`, etc.

## References

See `references/` for detailed guides:
- `directory-structure.md` — Full directory layout with file examples
- `layer-responsibilities.md` — What belongs in each layer
- `dependency-rules.md` — Import rules and PHPStan enforcement

