Skip to content
Development
Skill

/symfony-hexagonal-architecture

Symfony hexagonal architecture (ports & adapters) setup for Symfony 6.4 LTS, 7.4 LTS and 8.x: project structure, module scaffolding, layer responsibilities, dependency rules, version compatibility, progressive refactoring of legacy code. Use when: architecture, module, layer,

From plugin
symfony-hexagonal
3510 skills2 agents1 hook

Claude Code

$ npx -y skills add aligundogdu/symfony-hexagonal-skill --skill symfony-hexagonal-architecture --agent claude-code

SKILL.md

symfony-hexagonal-architecture.SKILL.md
name: symfony-hexagonal-architecture
description: "Symfony hexagonal architecture (ports & adapters) setup for Symfony 6.4 LTS, 7.4 LTS and 8.x: project structure, module scaffolding, layer responsibilities, dependency rules, version compatibility, progressive refactoring of legacy code. Use when: architecture, module, layer, hexagonal, scaffold, project structure, directory structure, new project, new module, bounded context, deptrac, Symfony version, upgrade"

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
  • User asks which Symfony/PHP version a pattern needs

Step 0: Detect Versions

Before generating any code, know the project's Symfony, PHP, Doctrine and PHPUnit versions (the plugin's SessionStart hook prints them; otherwise read `composer.lock`). Then follow `references/version-compatibility.md`:

  • Default baseline: **PHP 8.2 + Symfony 6.4 APIs** (runs on 6.4, 7.4 and 8.x)
  • Use newer features (7.3+ `DeduplicateStamp`, 7.4 `#[ExtendsValidationFor]`, PHP 8.4 `private(set)`, ...) only when the detected versions allow it
  • Never generate APIs removed in Symfony 8 (`Request::get()`, constraint option arrays, XML service config)

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 (write + read ports)
└── ReadModel/       # (optional) Plain read-side view objects returned by read ports

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

Infrastructure/{Module}/
├── Persistence/     # Doctrine repositories, Mapping/*.orm.xml
├── Security/        # Voters, user providers
├── Messaging/       # Transport adapters, middleware
└── ExternalService/ # HTTP clients, third-party APIs

Presentation/{Module}/
├── API/             # REST controllers (+ Request/ DTOs)
├── CLI/             # Console commands
└── GraphQL/         # GraphQL resolvers/types

Shared code lives in a `Shared` module per layer (`Domain/Shared/ValueObject/Money.php`, `Presentation/Shared/Bus/QueryBus.php`, ...).

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/attributes directly on entities?
- Which Symfony / Doctrine versions are installed (affects what the refactor can use)?

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/`, move mapping from attributes/annotations to XML 4. **Presentation last**: Thin out controllers, add `ApiResponseTrait` + `#[MapRequestPayload]` DTOs, apply `#[IsGranted]`

After each layer, verify the code still works (tests + `doctrine:schema:validate`) before moving to the next.

Legacy projects on Doctrine annotations (`@ORM\...`) cannot upgrade to ORM 3 anyway: moving the mapping to XML during the Infrastructure step unblocks that upgrade too.

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 the port interfaces in `Domain/{Module}/Port/` 3. Create the repository adapter + XML mapping in `Infrastructure/{Module}/Persistence/` 4. Register the mapping directory in `doctrine.yaml` and bind ports to adapters in `services.yaml` 5. Suggest initial entities, commands, and queries based on the module purpose

Key Rules

1. **Domain purity**: No `use Symfony\

Read more
@aligundogdu
Ships withsymfony-hexagonal

A Claude Code plugin that enforces hexagonal architecture (ports & adapters) in Symfony projects. Works with both new projects (full scaffolding) and existing projects (progressive, module-by-module refactoring).

3510 skills2 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
35
Star history of aligundogdu/symfony-hexagonal-skill on GitHub, a chart by star-history.com

Other skills on symfony-hexagonal.

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills12d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc13d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react3d252k
@facebook@facebookInstall Skill

Questions about symfony-hexagonal-architecture.

Which coding agents can use symfony-hexagonal-architecture?
symfony-hexagonal-architecture installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.