# Preconditions

This guide explains how to use **preconditions** in EventSourcingDB to ensure that events are only written when certain expectations are met. Preconditions allow you to **express business or consistency constraints declaratively** – **directly as part of a write request**.

## Why Preconditions Matter

In many systems, it's not enough to simply write an event. You often want to do so **only if certain conditions hold** – for example, that no prior events exist for a subject, or that no changes have occurred since your last read.

Preconditions let you **enforce such guarantees without additional roundtrips or manual checks**. They support use cases like **optimistic locking**, **subject initialization**, and **conflict detection** in concurrent environments.

## How Preconditions Work

Preconditions are **evaluated by EventSourcingDB as part of the same transaction that writes your events**. If **all preconditions are met**, the **events are written**. If **any of them fail**, nothing is written, and the **operation is aborted** with **HTTP status code `409 Conflict`**.

You can include preconditions by adding a `preconditions` array to the request body, alongside the `events` array.

## Available Precondition Types

EventSourcingDB supports the following preconditions:

### `isSubjectPristine`

This precondition **checks that a given subject has no events yet**. It is typically **used when introducing a subject for the first time** – for example, when acquiring a book or registering a new user. It ensures that the subject is empty and that no prior write has occurred.

```json
{
  "type": "isSubjectPristine",
  "payload": {
    "subject": "/books/42"
  }
}
```

Use this precondition when your event is meant to **initialize a stream and should not be duplicated**.

### `isSubjectOnEventId`

This precondition **checks that the most recent event for a subject has a specific ID**. It is used to implement **optimistic concurrency**: ensuring that no new events have been written to the subject since you last read it.

```json
{
  "type": "isSubjectOnEventId",
  "payload": {
    "subject": "/books/42",
    "eventId": "23"
  }
}
```

This is useful when writing a follow-up event that **assumes the subject is in a known state**. If another event has been added in the meantime, the write will be rejected – preventing lost updates or inconsistent state.

## Transactional Behavior

All preconditions are **evaluated as part of the same transaction** as the events. This **guarantees atomicity**:

- If **all preconditions pass**, **all events** are written.
- If **any precondition fails**, **no events** are written.

This makes preconditions a safe and expressive way to guard against race conditions and enforce domain invariants.

## Best Practices

- **Use `isSubjectPristine` when initializing a subject** to prevent accidental re-creation.
- **Use `isSubjectOnEventId` when updating a subject** based on prior reads to ensure consistency.
- **Don't solely rely on preconditions for business logic** – use them to enforce technical guarantees, not to replace domain modeling.
- Keep in mind that **preconditions are optional, but highly recommended** in collaborative or distributed environments.

## Designing with Preconditions

Preconditions help you **build safer, more predictable event-sourced systems**. They allow the **database to participate in consistency checks** – **reducing the need for custom locking logic and race-condition handling** in your application.

Used thoughtfully, they provide a clean and reliable foundation for modeling workflows, enforcing invariants, and coordinating concurrent operations.
