Event Sourcing in PHP

Event-sourced aggregates with #[EventSourcingAggregate]. Projections via #[ProjectionV2] — global, partitioned, or streaming. Non-blocking gap detection — concurrent access is never blocked. Projection emission with rebuild auto-suppression. End-to-end PII encryption across event store, broker, and structured logs.

Composer package · Laravel, Symfony, or Tempest · PostgreSQL or MySQL · RabbitMQ, Kafka, SQS, Redis, or DBAL outbox

What Ecotone provides

Capabilities relevant to event sourcing

How it compares

What Ecotone adds over a single-purpose tool

Each tool below is a capable choice for its slice. Ecotone covers the same ground and adds the operational layer around it — so aggregates, projections, sagas, and messaging share one model and one set of guarantees.

Spatie laravel-event-sourcing

Purpose-built for event sourcing inside a Laravel application.

Where Ecotone goes further than this library

  • Ecotone runs the same event-sourced aggregates, projections, snapshots, and replay — on Laravel or Symfony — and adds the operational layer for scale on top.
  • Non-blocking gap detection catches concurrent-commit events without blocking concurrent writes — late commits are never silently skipped.
  • Partitioned, parallel-worker rebuild across N workers — where a single-cursor replay processes the whole stream in one pass.
  • Projections can publish their own events as they apply changes — downstream read models and processes update in the same flow, avoiding an extra eventually-consistent hop. Automatically suppressed during a rebuild.
  • End-to-end PII encryption follows one #[Sensitive] field through the event store, the broker, and your structured logs.
EventSauce

A clean, framework-agnostic event-sourcing library.

Where Ecotone goes further than this library

  • Ecotone wraps the same event-sourcing core in one attribute-driven model that also delivers CQRS buses, async messaging, sagas, and cross-service distribution — without wiring separate libraries together.
  • A subscription engine that tracks each consumer's position for you.
  • Per-projection failure isolation — each projection gets its own copy of the event, so one failing projection never holds up the others.
  • Non-blocking gap detection that never blocks concurrent access, plus projections that can publish their own events — so dependents react in the same flow rather than via a separate eventually-consistent process.
  • End-to-end PII encryption across the event store, the broker, and your logs.
Patchlevel event-sourcing

A capable Doctrine-based event-sourcing library with per-subscription isolation.

Where Ecotone goes further than this library

  • Ecotone covers the same event-sourcing ground and adds the wider messaging fabric around it — a cross-service distributed bus, orchestration, and async across any broker.
  • Partitioned, parallel-worker rebuild within a single projection for very large streams — beyond a single cursor.
  • Non-blocking gap detection, on by default — concurrent access is never blocked.
  • End-to-end PII encryption that follows the field beyond the event store — across broker payloads and structured logs.
  • Projections can publish their own events as they update — dependent read models, sagas, and handlers react in the same flow instead of through a separate eventually-consistent process. Auto-suppressed during a rebuild so backfills don't re-fire them.
Ecotone

Scales with your event volume — from one cursor to N parallel workers.

  • Covers what every PHP event-sourcing library covers — event-sourced aggregates, projections, snapshots, replay — and adds the operational layer they don't.
  • Global tracked projections work for the early-stage system. As volume grows, switch to partitioned projections that rebuild in parallel across N workers: 50 million events that take 14 hours on a single-cursor rebuild finish in minutes when partitioned across 60 workers.
  • Streaming projections consume directly from Kafka or RabbitMQ Streams.
  • Blue-green deployments host the new projection version alongside the old one — atomic switch when ready, zero downtime.
  • Non-blocking gap detection catches concurrent-commit events without blocking concurrent writes, before they're silently skipped.
  • End-to-end PII encryption follows the same #[Sensitive] field through the event store, the broker, and your structured logs.

Frequently asked questions

Haven’t found what you’re looking for? Contact us

Ecotone provides a built-in event store on PostgreSQL or MySQL, event-sourced aggregates via #[EventSourcingAggregate], and projections via #[ProjectionV2] with global, partitioned, and streaming variants. Non-blocking gap detection means concurrent-transaction commits aren't silently skipped, without blocking concurrent writes. Projections can publish their own events as they update — so dependent read models, sagas, and handlers react in the same flow instead of through a separate eventually-consistent process; emission is automatically suppressed during a rebuild so consumers aren't flooded with historical duplicates. End-to-end PII encryption follows a single #[Sensitive] field through the event store, the broker payload, and your structured logs. As event volume grows, projections scale from a single cursor to N parallel workers via partitioning — without changing your domain code.
Events committed in concurrent transactions can be re-ordered relative to their commit timestamps — a transaction that started earlier may commit later. Without gap detection, the projection reads the visible event with the higher position, advances its cursor past the gap, and silently skips the event that committed later. Ecotone's GapAwarePosition records the gap and keeps advancing on the visible events without blocking concurrent writes; when the missing event becomes visible the projection applies it then — so concurrent-commit events are never silently dropped, and concurrent access is never blocked.
Yes — a projection can publish a new event the moment it applies a change (via EventStreamEmitter), and sagas, other projections, and event handlers react to it through the normal #[EventHandler]. That keeps dependent logic in the same flow instead of running a separate eventually-consistent process that polls the read model. Emission is automatically suppressed during a projection rebuild, so downstream consumers aren't flooded with historical duplicate events on backfill.
One #[Sensitive] attribute on an event field encrypts the value in the event store, on the wire over RabbitMQ / SQS / Redis / Kafka / DBAL outbox, and in your structured logs — because all serialization flows through one shared conversion pipeline. Crypto-shred a customer by deleting their key; their events become unreadable everywhere they live.

Be part of the change with EcotoneCurve

Unleash the power of Messaging in PHP
and push productivity to the higher level

Get started
Gradient
Shapes 1
Shapes 2
DiscordTwitterSupport and ContactTelegram