Skip to main content
Development

ADRs in practice: 3 templates, one Symfony project, one Git workflow

Which template to use? Where do the files go? How do you integrate them into PRs? A complete setup guide for a real Symfony project, with 3 formats compared on the same use case.

ADR MADR Workflow Git Symfony Documentation

This is part 2 of a series on ADRs. If you are new to the concept, start with article 1.

Setup in 5 minutes

# Via Homebrew (macOS)
brew install adr-tools

# Via pip (Linux, Python available everywhere)
pip install adr-tools-python
cd my-symfony-project
adr init
adr new "Use doctrine/migrations instead of Flyway"

Three templates, one decision

Nygard — the minimalist

# ADR-0003 — Use Doctrine Migrations instead of Flyway

Date: 2026-03-18
Status: Accepted

## Context

Our Symfony 5 application uses Flyway for SQL migrations.
Flyway requires a JVM — incompatible with our minimal PHP/Docker stack.

## Decision

Adopt doctrine/migrations as a replacement for Flyway.

## Consequences

- Native Symfony integration (php bin/console doctrine:migrations:migrate)
- No JVM dependency in the PHP Docker image
- Migration of 23 existing Flyway scripts to Doctrine format (effort: 2 days)
- Built-in rollback via the down() method

MADR — the explicit comparison

# ADR-0003 — Use Doctrine Migrations instead of Flyway

Date: 2026-03-18
Status: Accepted

## Context and problem

We are migrating to Symfony 7. The team uses Flyway (Java tool) for SQL migrations.
Flyway requires a JVM — incompatible with our minimal PHP/Docker stack.

## Options considered

- **Option A**: Keep Flyway (external tool, JVM required)
- **Option B**: Adopt doctrine/migrations (native Symfony, PHP)
- **Option C**: Manual versioned migrations (git + SQL)

## Outcome

Option B selected: doctrine/migrations.

### Advantages

- Native Symfony integration (`php bin/console doctrine:migrations:migrate`)
- No JVM dependency in the PHP Docker image
- Built-in rollback via `down()` method

### Disadvantages

- Migration of 23 existing Flyway scripts to Doctrine format (estimated: 2 days)

Y-Statement — the structured sentence

In the context of a Symfony 5 to 7 migration with a minimal Docker image constraint,
facing Flyway's JVM dependency,
we decide to adopt doctrine/migrations
in order to eliminate the JVM dependency and integrate migrations into the native Symfony workflow,
accepting the migration effort for 23 existing scripts (estimated 2 days).

Comparison table

TemplateComplexitySectionsBest for
NygardLow3Quick decisions, solo projects, small teams
MADRMedium6Comparing 3+ options, structural decisions
Y-StatementMinimal1Clear decisions, lightweight traces, documented rejections

ADR lifecycle

  • Proposed — written, not yet validated
  • Accepted — decision made and applied
  • Deprecated — no longer relevant, no replacement
  • Superseded — a new ADR replaces this one
  • Rejected — evaluated and discarded

Git integration

git commit -m "docs(adr): add ADR-0003 - switch to doctrine/migrations"
git commit -m "docs(adr): accept ADR-0004 - Redis for session storage"
git commit -m "docs(adr): supersede ADR-0001 with ADR-0006"

Require an ADR alongside any PR that modifies composer.json, database structure, or infrastructure configuration.

Lightweight governance

Three questions to answer once: who can create, who validates, what is the acceptance criterion.

The complete example project is available on the CodexLab GitHub repository.

Next in the series: how to have the machine enforce your decisions — PHP fitness functions, CI/CD, and automatic drift detection.

In the same vein