Skip to main content
Aggregates are the unit of consistency inside EventDBX. They own their events, snapshots, and Merkle trees. Good aggregate design keeps writes simple and isolates failure domains.

Naming and identifiers

  • Use stable, business-meaningful IDs (invoice-991, org_42). Avoid database auto-increment integers—they leak implementation details.
  • Embed shard hints if you plan to distribute aggregates across filesystems: order:us:10023.
  • Store identifiers in metadata (@tenant, @channel) so plugins can route events without parsing payloads.

Lifecycle

Create aggregates explicitly with an initial event:
dbx aggregate create person p-991 person_registered --payload '{"first_name":"jane","last_name":"doe"}'
Append new facts as they occur:
dbx aggregate apply person p-991 person_updated --payload '{"status":"active"}'
Check current state (with optional history):
dbx aggregate get person p-991 --include-events
Delete operations are rare; prefer terminal events (invoice_voided) that mark state without removing history. If you must retire an aggregate, archive it (dbx aggregate archive <type> <id>) or remove only when it has no events (dbx aggregate remove requires version 0).

Metadata conventions

{
  "@actor": "svc-billing",
  "@tenant": "northwind",
  "@source": "invoice-service",
  "@replay": false
}
Reserve the @ prefix for extension metadata. Everything else belongs to your business domain. Consistent metadata enables search, audit, and replication filters. Use namespaced keys (@trace, @tenant) to keep user hints distinct from system metadata.

Anti-patterns to avoid

  • God aggregates: packing unrelated concerns (billing + identity + compliance) into one aggregate explodes payload size and causes contention.
  • Cross-aggregate transactions: EventDBX is intentionally single-write-path. Model relationships through events (e.g., order_paid referencing payment_id) and have read models enforce constraints asynchronously.
  • Mutable fields: never overwrite data in place. Emit a new event (invoice_amount_adjusted) so the audit trail stays truthful.
Thoughtful aggregate design pays dividends when you need to replay history, verify integrity, or explain how a piece of state changed over time.