Skip to content

DDD with Symfony. Without building it all yourself.

Symfony ships Doctrine, Messenger, and Dependency Injection. But no architecture for Bounded Contexts, no clear separation of Domain and Infrastructure, no generated DDD foundation. Jardis adds exactly that layer.

Symfony gives you tools. Not the architecture.

Doctrine is a solid Data Mapper. Messenger is a reliable bus. But DDD is more than tools. It is structure.

Doctrine Entities are not Domain Entities

Doctrine mapping annotations, lifecycle callbacks, and flush cycles permeate your entities. In practice, persistence logic blends with business rules. The domain layer becomes dependent on Doctrine, even though it should not be.

Weeks of boilerplate per Bounded Context

Commands, handlers, events, repositories, API contracts: all by hand. Every new Bounded Context means dozens of files that must be created, wired, and kept consistent manually. That costs weeks, not minutes.

Bounded Contexts only exist on the whiteboard

Symfony Bundles are not Bounded Contexts. In practice, entities, services, and repositories end up in the same src/ directory. Domain boundaries are folder conventions that nobody follows under time pressure. A service reaches into three domains, and nobody notices.

How Jardis brings DDD to Symfony projects.

Symfony stays responsible for HTTP, routing, DI, and messaging. Jardis generates the domain architecture that Symfony does not ship.

DOMAIN LAYER

Dedicated Domain Entities alongside Doctrine

The builder generates 3-layer Entities as standalone PHP packages. Your domain logic lives separated from Doctrine mappings. Persistence becomes an infrastructure concern, and the domain stays clean. Doctrine remains as the persistence layer but no longer dictates your architecture.

CQRS AND EVENTS

Generated Commands, Queries, and Events instead of manual wiring

Jardis generates the complete CQRS infrastructure in PHP: Commands, Command Handlers, Queries, Query Handlers, and Domain Events. The output is compatible with Symfony Messenger, but the structure comes from the builder. No manual creation of handler classes for every use case.

BOUNDED CONTEXTS

Physical domain boundaries instead of folder conventions

Every Bounded Context becomes a standalone PHP package with its own dependency structure. The builder enforces isolation at the filesystem level. A service cannot accidentally reach into a foreign domain. This is architecture, not a guideline.

See what three files turn into.

Three definition files in, a complete bounded context out. Browse the generated code.

E-Commerce / Sales
schema.yaml
# Database Schema — Sales Bounded Context
# This file defines the persistent storage structure.

schema:
  domain: ECommerce
  boundedContext: Sales

tables:
  order:
    columns:
      id:
        type: integer
        primary: true
        autoIncrement: true
      public_id:
        type: uuid7
        unique: true
      customer_email:
        type: string
        length: 255
      status:
        type: string
        length: 32
        default: "draft"
      total_amount:
        type: integer
      currency:
        type: string
        length: 3
        default: "EUR"
      created_at:
        type: datetime
      updated_at:
        type: datetime
        nullable: true

  order_item:
    columns:
      id:
        type: integer
        primary: true
        autoIncrement: true
      order_id:
        type: integer
        foreignKey:
          table: order
          column: id
          onDelete: cascade
      product_name:
        type: string
        length: 255
      sku:
        type: string
        length: 64
      quantity:
        type: integer
      unit_price:
        type: integer
      line_total:
        type: integer
Files
Definitions (Input)
Generated Code (Output)
BUILDER OUTPUT
80%
infrastructure code generated per Bounded ContextEntities, Aggregates, Commands, Queries, Events, API Contracts, and the Repository Pipeline. Generated instead of hand-written in Symfony.
3x
faster setup for new domains
0
Doctrine dependencies in the domain layer
ARCHITECTURE
100%
Hexagonal architecture from day oneEvery generated file follows hexagonal architecture. No deviation, no shortcuts, no Doctrine annotations in the domain.

Why Symfony teams use Jardis for DDD.

Not because Symfony is wrong. But because DDD architecture demands more than Symfony ships.

> Standalone Packages

Bounded Contexts as PHP Packages

Each domain becomes a standalone package with its own structure. Order, Payment, Compliance: physically separated instead of mixed in one src/ directory. Teams work independently.

> Instantly Productive

Domain architecture in minutes instead of weeks

New Bounded Context? Define the schema, start the builder, generate production-ready code. No weeks of creating commands, handlers, events, and repositories by hand.

> Consistent Structure

Every Bounded Context follows the same pattern

No debates about folder structure, naming, or layer separation. The builder generates consistent architecture. New developers find their way immediately because every domain is structured the same way.

Ready to bring DDD into your Symfony project?

Join the Waitlist

Structure costs less than chaos.

Free Trial

Try Jardis 7 Days Free

Point Jardis at your real domain. Discovery, structure, and your first platform build.

Join Waitlist
20 Discovery Runs
5 Structure Builds
1 Platform Build
All Jardis packages as open source
Jardis Base
€29per month

The complete DDD architecture with all classes and contracts. Your team ships features, not infrastructure.

Join Waitlist
Unlimited Discovery Runs
Unlimited Structure Builds
All 26 Jardis packages included
PHPStan Level 8 from day one
Jardis Pro
€180per month

The complete business logic with handlers, validation, and pipelines. What used to be a sprint is now a build.

Join Waitlist
Everything from Jardis Base
Commands, queries, and events fully implemented
Platform code in seconds instead of weeks
Additional Runs for €89 each
Enterprise

More than 20 Platform Builds per month?

Let's talk

Be there when Jardis launches.

Sign up. You'll get access as soon as we go live. Including a free trial.

100+ developers are already waiting for launch

Curious how Jardis works?

Discover Jardis

Frequently Asked Questions

Answers to the most important questions about Jardis and Symfony in a DDD context.

No. Symfony stays responsible for HTTP, routing, dependency injection, security, and messaging. Jardis generates only the domain layer: PHP Entities, Aggregates, Commands, Queries, Domain Events, and the Repository Pipeline. These live as standalone packages next to Symfony's src/ directory.