# Snapshots and Performance

This guide explains how to use **snapshots** in event-sourced systems to improve **performance** and reduce **overhead during replay**. While the event store treats all events as **immutable** and **equally important**, applications can introduce **snapshots** as a way to avoid rebuilding state from the beginning of a stream every time. This is especially useful for aggregates with **long histories** or systems with **high throughput**.

**Snapshots do not need to be a native concept of the event store** – there is no need for a special snapshot type or storage mechanism built into the event store. Instead, **snapshots can be represented as ordinary events** that follow the same structure and guarantees as any other event. This simplicity allows you to **define, write, and consume snapshots using the same tools and APIs** you already use for regular events.

> **Try it with EventSourcingDB**
>
> This is how EventSourcingDB handles snapshots: there is no dedicated snapshot mechanism, a snapshot is simply an event – see **[Snapshots](/docs/eventsourcingdb/snapshots)**.

## Why Snapshots Matter

In an event-sourced system, the current state of an entity or aggregate is typically reconstructed by **replaying its entire event history**. This works well for short streams, but becomes inefficient as the number of events grows.

For example, **rebuilding an aggregate with 50 events may take milliseconds – but one with 10,000 events could take much longer**. This adds latency to command processing, reduces responsiveness, and increases CPU usage under load.

**Snapshots solve this by capturing the derived state at a given point in time**. Instead of replaying all events, the application can **load the most recent snapshot and replay only the events that occurred afterwards**. This reduces the cost of reconstruction and makes **performance predictable**.

## Modeling Snapshots as Events

Modeled this way, a **snapshot is just an event** – typically with a special event type such as:

```
com.example.library.book-state-snapshot.v1
```

The snapshot contains a **complete representation of the current state** in its `data` field. It can be written at any point, usually after a fixed number of domain events, or when the application detects a **significant state change**.

**Snapshots must include the same `subject` as the stream they refer to**. This ensures that they are ordered correctly and replayed in context with the rest of the stream.

Because the event store does not treat snapshot events differently, your application is responsible for:

- **Choosing when to create a snapshot**
- **Ensuring that the snapshot is a valid representation of prior events**
- **Deciding how to identify and load the most recent snapshot**

This flexibility allows you to **design snapshot logic that fits your domain and performance requirements** – without introducing special-case behavior in the event store.

## Creating and Writing Snapshots

The process for creating a snapshot usually looks like this:

1. **Rebuild the aggregate by replaying its events as usual**
2. **Serialize the current state into a snapshot object**
3. **Write the snapshot to the event store using a dedicated event type**
4. **Optionally tag the snapshot with metadata, such as version or timestamp**

You can use the **same write API as for any other event**, including schema validation if desired. **Snapshot events typically appear less frequently than domain events**, so they are easy to manage and analyze.

## Reading Snapshots During Replay

To take advantage of snapshots during replay, the application must:

1. **Read the most recent snapshot for the subject**
2. **Restore the state from the snapshot**
3. **Read all subsequent events and apply them incrementally**

This requires the application to **distinguish snapshot events from domain events**. A common pattern is to **filter by event type prefix or suffix**, or to **tag snapshot events with a known schema**.

If all events are **ordered by a global `id`**, it is easy to find the point in the stream after which the remaining events need to be applied. A **strict and stable ordering** simplifies the logic for partial replays.

> **Try it with EventSourcingDB**
>
> EventSourcingDB orders all events strictly by their global `id`, and **EventQL** can query for the latest snapshot using **`ORDER BY e.id DESC TOP 1`** – see **[EventQL](/docs/eventsourcingdb/eventql)**.

## Performance Considerations

The use of snapshots significantly **reduces the time needed to rebuild aggregates or read models** – especially when combined with other performance strategies:

- **Keep snapshot intervals balanced**: too frequent increases storage; too rare increases replay cost
- **Use simple, flat structures in snapshot `data` fields for fast deserialization**
- **Avoid including redundant or computed fields that can be derived from events**
- **Compress large snapshots if necessary (application-side)**
- **Create snapshots asynchronously if synchronous writes add latency**

Even if the event store is **optimized for sequential access and streaming**, **reducing the number of events that must be loaded and processed** is often the most effective way to improve end-to-end performance.

## Snapshots Are Optional, but Useful

Not all systems need snapshots. For **short-lived entities or infrequently accessed aggregates**, replaying from the beginning may be acceptable. But as your system grows, and **certain streams accumulate thousands or millions of events**, snapshots become a **critical tool for keeping replay fast and resource usage predictable**.

By **modeling snapshots as regular events and handling them at the application level**, you retain full control – without compromising the **consistency, traceability, or semantics of the event stream**.
