Concepts

Event store

Talk to an event store expert ↗

Most databases keep the answer. They store how things are right now, and every update overwrites what came before. When the business later asks how it got there, that history is gone.

An event store keeps the history instead. Every change is recorded as an immutable event, in order, and current state is derived from it. A purpose-built event store also validates every new event against that history before accepting it, so business rules hold at the moment of the write.

DATABASE · CURRENT STATE
One row, overwritten

Each change replaces the last value. The row says where the student is today, not how they got there.

IDSTATUSCOURSESCITY
s-1registered0Amsterdam
0 earlier values are gone for good.
EVENT STORE · EVERY CHANGE
An ordered history, appended

Each change is an immutable event, written after the last one and never written over.

1,204,326StudentRegisteredstudent:s-1
1 of 1 events kept, in order, for as long as the history matters.

This page explains what an event store is, what it guarantees, how event store databases differ from the databases and platforms teams often use instead, and what it takes to run one at billions of events.

What is an event store?

An event store is a database that keeps every change in your application as an immutable, ordered event, retrieves one entity’s history efficiently even at billions of events, and validates every new event against that history before accepting it.

Any database can accumulate records, and none of them becomes an event store by doing so. The name is earned by the two operations that must hold under production load. Retrieval has to isolate one entity’s ordered history from billions of records during reads at latencies a live application can tolerate, and every append must be validated against the existing history at write time.

THE SHAPEAppend, never overwrite

Each change goes after the last one. Recorded events never change.

1StudentRegisteredIMMUTABLE
2CourseCreatedIMMUTABLE
3CourseSubscribed
4AddressChanged
5CourseSubscribed
01 · RETRIEVEOne entity, out of billions

An index picks out only the events about the entity at hand.

student:s-10 of 2,400,000 read
02 · VALIDATECheck before accepting

The store rejects an append when the history it was decided on has changed.

#read: 29 of 30 seats takenMARKER @118
120CourseSubscribed s-12MATCHES
decide: one seat left, subscribe s-41
Any database can hold events. Two operations make it an event store, and both have to hold under production load.

What is an event?

An event is a record of something significant that happened in your system, written in past tense, for example RegistrationConfirmed or PaymentRejected. These are facts and are never changed afterwards. What happened, happened. When circumstances change, a new fact is appended after the old one rather than written over it. Each event carries its type, its position in the store, when it was recorded, the identifiers or tags that link it to the entities it concerns, and its payload.

TYPE
CourseSubscribed
POSITION
1,048,577
TIMESTAMP
2026-11-05T09:14:22.318Z
TAGS
student:s-1course:c-9
PAYLOAD
{ "studentId": "s-1", "courseId": "c-9", "semester": "2027-spring" }
TYPEWhat happened, in the past tense

Named for the business fact, not the technical change. Handlers and queries select on it.

HISTORY OF student:s-1
StudentRegisteredcity: Amsterdam
CourseSubscribedcourse: c-9
CourseSubscribedcourse: c-4

How is an event store different from a database?

A traditional database stores the answer, while an event store stores everything that produced said answer. Where a relational database holds an entity’s current status and nothing else, an event store holds every change that produced that status, in sequence, permanently. Applications built on event sourcing derive their current state from those events instead of keeping it in mutable rows.

An event store guarantees consistency at the moment of append, immutability once an event is written, and strict ordering on read. The first is crucial because every new event is checked against the history already recorded, so conflicting facts are rejected before they enter the record rather than untangled after they corrupt it.

History also gives auditors and regulators a complete account of what happened and in which order, without a separate audit log that can drift away from the data it describes.

Keeping history pays off twice. A live application can act on it while a request is still in flight. And when the business asks a question nobody anticipated at design time, the answer is read from the events instead of being wished back into existence.

DATABASE · ONE ROW1 VALUEKnows today, and nothing before it0123day 1day 10day 20todayoverwrittencourses: 3
Courses on day 12?that value was replaced
?
EVENT STORE · SIX EVENTSEVERY VALUEKnows every day, from the events0123day 1day 10day 20today+1+1-1+1+1
Courses on day 12?3 of 6 events applied
2
The row holds the answer to one question. The log holds the answers to all of them, including the ones nobody has asked yet.

Can’t I use any database as an event store?

You can. An event store is a log with an index in front of it, and any database can hold a log, one table with a row per event and a position column. Teams have run event-sourced systems on PostgreSQL, SQLite, MongoDB and DynamoDB, and at a small scale it works.

The work is in what you add on top, so that both operations still hold with several writers, several application instances and a few billion events. The two boards below show those pieces for PostgreSQL and for SQLite, the two most common do-it-yourself choices. A piece marked “you build it” is code you write, test and operate. A piece marked “not available” is a limit you design around.

PostgreSQLCLIENT / SERVER8 TO BUILD
YOU BUILD ITGlobal order under concurrent writers
YOU BUILD ITConditions across entities
YOU BUILD ITCatch-up subscriptions
YOU BUILD ITSnapshots
PostgreSQLtable · unique constraint · index
YOU BUILD ITYears of history
YOU BUILD ITHigh availability
YOU BUILD ITRouting to the warm instance
YOU BUILD ITRewriting events for erasure
SQLiteEMBEDDED, ONE FILE5 TO BUILD · 2 MISSING
BUILT INGlobal order under concurrent writers
YOU BUILD ITConditions across entities
YOU BUILD ITCatch-up subscriptions
YOU BUILD ITSnapshots
SQLitetable · unique constraint · one writer
YOU BUILD ITYears of history
NOT AVAILABLEHigh availability
NOT AVAILABLERouting to the warm instance
YOU BUILD ITRewriting events for erasure
You build itBuilt inNot available

The honest summary is that PostgreSQL gives you a correct event store once you have built ordering, subscriptions, snapshots, retention and failover around it, and SQLite gives you ordering for free because it has one writer, then stops at one machine for the same reason. Axon Server is that list built once, as one system, with the routing that keeps it fast.

Is it slow to event source millions of events?

It would be if systems actually did that on every request, and the reason they do not is a two-layer mechanism. Consider an entity whose history spans five thousand events. With snapshots taken every hundred events, the first four thousand nine hundred are compressed into a single stored state. When a request arrives, the application loads that snapshot, applies only the few dozen events recorded since, and responds fast, without touching the thousands of events underneath.

The second layer is aggregate caching, which removes the event store from the hot path on reads entirely for most cases. When the same instance of an application is always responsible for the same entity, that entity’s state is often still in memory from the last request, so the application applies its decision directly from cache and sends only the resulting append to the store. The consistency check in the event store makes this safe, because it verifies that the application’s view of history is current before accepting the event.

NO SNAPSHOTSource everything

Apply every event since the entity was created.

event 1event 5,000
0events applied before the decision
SNAPSHOT POLICYLoad snapshot, apply the tail

With a policy of one snapshot per 100 events, events 1 to 4,900 are folded into one stored state.

SNAPSHOT @ 4,900
event 1event 5,000
0events applied before the decision
AGGREGATE CACHEState still in memory

Same entity, same instance, state still in memory from the last request. The store only verifies the append.

IN MEMORY · 0 EVENTS READ
event 1event 5,000
0events applied before the decision
Snapshots buy speed without spending history. All 5,000 events stay in the store, ready to rebuild a snapshot or answer a replay.

Underneath is the operative word, because those events are compressed out of the hot path, not thrown away. If a bug corrupted the snapshots, the full history still exists to source from scratch and rebuild them correctly, and if a new analytical question arrives, the complete record is there to replay. Snapshots buy speed without spending history.

What does Axon Server add as an event store?

Axon Server brings the pieces teams otherwise build around a general-purpose database into one system.

01

Consistency on every append, per aggregate or across entities with dynamic consistency boundaries.

02

Fast per-entity reads out of billions of events, through dedicated indexes and snapshots.

03

High availability through Raft-based replication groups and dedicated node roles.

04

Histories that grow for years, with tiered storage moving older segments off primary disks.

05

Routing for commands, events and queries in the same system, so commands for the same entity keep reaching the same instance.

TWO SYSTEMSBroker and database, routed apart

The broker does not know which instance holds the order’s state.

AXON SERVERRouting and storage in one system

The routing key sends every command for o-7 to the same instance, as long as the set of instances is stable.

COMMANDS · ORDER o-7
AddItem1
ApplyDiscount2
ConfirmOrder3
ROUTER
Generic brokerround robin
APPLICATION INSTANCES
instance 1
idle
instance 2
idle
instance 3
idle
EVENTS READ0to handle 0 commands
A cache only pays off if the next command finds it. When the system that routes the command also knows where the entity lives, it does.

How does Axon Server store events?

Axon Server is built around an append-only log. Its storage is organized in layers, each with one job.

First, events are appended to segment files. Each context has its own event store on disk. New events are written to the end of the current segment, 250 MB by default, and closed segments are never changed in place. Every event receives a position in one global sequence.

Second, indexes find one entity’s history. In aggregate-based contexts, a global index locates an aggregate’s latest event, and per-segment pointers lead back to the earlier ones, skipping the segments in between. Contexts built for dynamic consistency boundaries (DCB) use a different index, one built to answer criteria over tags and event types.

Third, snapshots live in their own store. A snapshot holds the computed state of an entity at a known position, so loading it means reading the snapshot and only the events recorded after it, in one operation. The application decides when to take a snapshot. Since Axon Server 2026.1, DCB contexts source snapshot and events together as well.

Fourth, older data can move to other tiers. On each node, tiered storage moves closed segments to other storage based on time or size, so recent segments stay on fast disks and older ones on cheaper storage, while the full history stays readable. With secondary nodes in the cluster, primary nodes can drop the oldest data entirely.

01 · SEGMENTSAppend to the log

New events go to the end of the current segment. Closed segments are never changed in place.

segment 1CLOSED
segment 2CLOSED
segment 3CLOSED
segment 4OPEN
02 · INDEXFind one entity

In aggregate-based contexts, a global index points to the latest event and per-segment pointers lead back, skipping segments in between. DCB contexts use a different index.

order:o-7→seg 4 · latest←seg 3←seg 2←seg 1
03 · SNAPSHOTSSkip the long tail

Computed state at a known position, kept in its own store. The application decides when to take one.

order:o-7 @ 800order:o-7 @ 900with a policy of one snapshot per 100 events
04 · TIERSKeep years of history

Closed segments move off primary disks by age or size.

PRIMARY · FAST DISK
segment 1segment 2segment 3segment 4
OTHER TIER · ARCHIVE
2019 … 2025
Each layer has one job. Together they keep appends cheap, reads narrow, and the full history available for as long as the business needs it.
SOURCINGOne entity, one decision

The index returns only student s-1’s events, folded into current state.

REPLAYAll history, one new question

A cursor reads the whole log in order to build a view nobody planned for.

ONE GLOBAL LOG · EVERY ENTITY5 OF 10 READ
1StudentRegisteredstudent:s-1
2CourseCreatedcourse:c-9
3StudentRegisteredstudent:s-2
4CourseSubscribed · c-9student:s-1
5CourseCreatedcourse:c-4
6CourseSubscribed · c-9student:s-2
7AddressChangedstudent:s-1
8CourseSubscribed · c-4student:s-1
9CourseSubscribed · c-4student:s-2
10CourseUnsubscribed · c-9student:s-1
MODEL · STUDENT s-1
FOLDED FROM 0 EVENTS
registered?
city?
courses?
Fast because it is narrow. Five events about other entities are never touched.

Reading follows the two paths the figure shows. Sourcing reads one entity’s events, bounded and fast, to make a decision. Streaming reads the global log from a tracking token onward, which is how event processors keep projections up to date and how a replay rebuilds a view from the very first event.

How does an event store keep appends consistent?

Every append to Axon Server can carry a condition. Before an event reaches the store, the application decides what has to be true for that event to be valid and attaches that requirement to the append. The store evaluates the condition against the current history at the moment the append arrives, rather than trusting whatever the application assumed was true when it issued the request. If the condition fails, nothing is written, and the application re-reads and decides again. No cleanup job, no deduplication logic downstream, and no idempotency key bolted on.

In aggregate-based contexts, the condition is the aggregate’s sequence number, so two writers that both read sequence 41 cannot both append 42. In DCB contexts, it is an append condition made of event criteria over tags and types plus the consistency marker returned when the events were read. The append fails if any event matching the criteria arrived after that marker.

The second form lets one rule span several entities, such as a course’s capacity and a student’s subscription limit, without sagas and without fixing aggregate boundaries before the first event is written.

AGGREGATE CONTEXTSAggregate sequence number

Two writers that read sequence 41 cannot both append 42.

DCB CONTEXTSAppend condition

Criteria over tags and types, plus the marker from the read.

TWO WRITERS
WRITER AREAD

loaded order o-7 at sequence 41

WRITER BREAD

loaded order o-7 at sequence 41

EVENT STORE
40ItemAddedorder:o-7
41ItemAddedorder:o-7
WHAT THE STORE DOES
Both writers decide on the same state.

How does Axon Server stay available?

In a cluster, Axon Server nodes form replication groups that use the Raft protocol. Each group elects a leader, and an append is confirmed once a majority of the group’s primary nodes has stored it, plus any active backup nodes the group is configured to wait for, so losing one primary node out of three costs neither data nor availability. Nodes can also take other roles. Active and passive backup nodes keep copies of the event store for recovery, secondary nodes keep the full history so primary nodes only need to hold recent segments, and messaging-only nodes route messages without storing events. Clients reconnect to another node automatically.

01Leader receives the append
02Replicated to the group
03A node goes down
04It returns and catches up
APPLICATIONAxon Framework clientappend event 7
REPLICATION GROUP · 3 PRIMARY NODESMAJORITY = 2
axonserver-1LEADER

writes event 7

axonserver-2

waiting

axonserver-3

waiting

An append is confirmed once a majority of the primary nodes has stored it. With three primary nodes that is two. Losing one costs no data and no availability.

Why one system
for events and messages

Because in a live event-sourced system, where a message is handled determines how fast the history can be used. Applications do not exchange only events, since a command such as “change my address” is the intent to do something, and the event is the proof that it happened. That intent has to reach the right place, because aggregate caching only works when requests for the same entity consistently land on the same application instance, where that entity’s state is already warm in memory. Route the command elsewhere and the cache is cold, the application sources from scratch, and the speed the architecture promised evaporates.

Splitting storage and routing across two systems means keeping two views of ownership and order aligned with each other, which is yet another distributed-systems problem acquired for no benefit. Combining them means the knowledge exists once, which is why Axon Server embodies both jobs in a single integrated system.

The same history also feeds analysis. Axoniq Insights lets data and business teams query event history directly, so a new question does not have to become a new projection.

Talk to an expert

🤔
Frequently

asked
questions

🤔
Frequently asked

questions

What is an event store in simple terms?

An event store is a system that saves every change in your application as an immutable, ordered event rather than overwriting current state. It retrieves history efficiently even at billions of events and validates each new event against the existing history before accepting it.

Is Kafka an event store?

No. Kafka is a message log built to move data through at high rates, while an event store is built to be a source of truth. Kafka offers no consistency guarantees on append and no efficient index for retrieving one entity’s complete history, which are the two capabilities that define an event store. See Axoniq and Apache Kafka.

Can I use Postgres or MongoDB as an event store?

At a small scale yes, and both have limitations. Gap-free ordering under concurrent writers, consistency validation on every append, and efficient per-entity history retrieval all become application logic you build and maintain rather than properties of the storage engine. MongoDB fits naturally on the read side instead, holding the projections built from the event store.

How does an event store handle GDPR if events can’t be deleted?

Through crypto shredding or event transformation. Crypto shredding makes encrypted personal data unreadable by destroying its encryption key. Event transformation removes or replaces the affected personal fields by writing new versions of the events, while preserving the surrounding event history. Both approaches aim to meet erasure requirements without discarding the record of what happened.

Does Axon Server support dynamic consistency boundaries?

Yes. DCB contexts have been fully supported since Axon Server 2025.2, and existing contexts can be converted since 2026.0, including contexts with applied event transformations since 2026.1. DCB is a licensed capability, available from the Team plan upward. Applications need Axon Framework 4.12 or later to connect to a DCB context, and Axon Framework 5 to use tags, criteria and append conditions. See the dynamic consistency boundary page.

How do event stores compare?

Many systems can hold events. Fewer are designed around the operations that define an event store. The table compares Axon Server with other purpose-built event stores, event sourcing libraries, general-purpose databases used as event stores, and two systems that are often mistaken for one. It reflects each product’s public documentation as of November 2026.

YesPartialDIY: you build it on general primitivesNon/a or undocumented
SystemBuilt for event sourcingOptimistic appendDCB append conditionsPer-entity readsGlobal orderCatch-up subscriptionsSnapshotsClustering and HAEvent transformationCommand and query routingLicense and hosting
PURPOSE-BUILT EVENT STORES
Axon ServerAxoniqYesYesYes1YesYesYesYesYes2Yes2YesFree for non-production, paid self-hosted plans, managed cloud
KurrentDBformerly EventStoreDBYesYesPartial3YesYesYesNo, patternYes4Partial5NoSource-available Kurrent License, Kurrent Cloud
EventSourcingDBthe native webYesYesYesYesYesYesNo, patternNo6NoNoClosed source, free up to 25,000 events
UmaDBDCB-native storeYesYesYesYes, by queryYesYesn/a, undocumentedn/a, undocumentedn/a, undocumentedNoMIT or Apache 2.0, self-hosted
EVENT SOURCING LIBRARIES
Marten.NET library on PostgresYesYesYesYesPartial7YesYesPartial, via PostgresYes, maskingNoMIT, runs on any Postgres
Akka PersistenceJVM libraryYesPartial8NoYesNoYesYesYes, Akka ClusterPartial, adaptersPartial8BSL 1.1, Akka platform
GENERAL-PURPOSE DATABASES USED AS AN EVENT STORE
PostgreSQLappend-only tableNoDIY9DIYYes, indexDIY9DIYDIYPartial9DIYNoPostgreSQL License, many managed offerings
MongoDBevent documentsNoDIYDIYYes, indexNoPartial10DIYYes, replica setsDIYNoSSPL, MongoDB Atlas
Amazon DynamoDBevent itemsNoYes, conditionsPartial11YesNoPartial11DIYYes, managedDIYNoProprietary, AWS only
Azure Cosmos DBevent documentsNoYes, ETagPartial12YesNoPartial12DIYYes, managedDIYNoProprietary, Azure only
OFTEN MISTAKEN FOR AN EVENT STORE
Apache Kafkastreaming platformNoNo13NoNo13No, per partitionYesNoYesNo13NoApache 2.0, Confluent Cloud, Amazon MSK
Temporalworkflow persistenceNo14n/an/an/an/an/an/aYesn/an/aMIT, Temporal Cloud

Scroll sideways to see every column.

  1. Axon Server. DCB contexts append with an append condition: event criteria over tags and types plus a consistency marker. Fully supported since 2025.2, and existing contexts can be converted since 2026.0. DCB is a licensed capability, available from the Team plan upward.
  2. Axon Server. Clustering and replication groups depend on the license. Persistent Event Transformation replaces or deletes events in aggregate-based contexts; since 2026.1, transformed contexts can be converted to DCB as well.
  3. KurrentDB. Multi-stream appends check an expected version per stream. Since 26.1 an append can also carry expected versions for streams it does not write to. That covers some cross-entity rules, but conditions are stream-based, not tag or query based.
  4. KurrentDB. Clustering requires an Enterprise license from version 26.2, per Kurrent’s licensing announcement.
  5. KurrentDB. Redaction is a separate tool run against a running server, once per node: licensed through 26.1, free from 26.2. Streams can be deleted or truncated and scavenged.
  6. EventSourcingDB. The documentation states high availability is planned, not yet available.
  7. Marten. The global sequence is a Postgres sequence, which can have gaps. The async daemon tracks a high water mark to handle them.
  8. Akka Persistence. Consistency comes from a single writer per entity through Cluster Sharding, not an expected version from the client. Sharding routes commands to entities, but there is no command or query bus.
  9. PostgreSQL. Expected versions usually mean a unique (stream, version) constraint. Sequences are not transactional, so positions can have gaps and become visible out of commit order. Automatic failover needs external tooling or a managed service.
  10. MongoDB. Change streams give live subscriptions, but resuming depends on oplog retention, so catching up from the first event is up to you.
  11. DynamoDB. Transactions with condition checks across up to 100 items can emulate some multi-entity rules. Streams keep records for 24 hours.
  12. Cosmos DB. Transactional batches are atomic within one logical partition key, and the change feed is ordered per partition key.
  13. Kafka. A producer cannot append on the condition of an expected offset, reading one entity means scanning a partition, and records cannot be rewritten in place.
  14. Temporal. A durable workflow engine. Its event history is an internal log per workflow execution, stored in Cassandra, MySQL or PostgreSQL and capped at 51,200 events. It is not a store for application domain events.

Get Started with Axoniq

Run your event store on Axon Server

Validated appends and fast per-entity retrieval are the operations a general-purpose database makes you build. Axon Server brings storage, consistency, replication and routing into one system, so your team spends its time on the business problem.