---
title: StartAtTail
editUrl: https://github.com/Cratis/Chronicle/edit/main/Documentation/reactors/start-at-tail.mdx
description: Keep a new side-effecting reactor from acting on events that predate its first registration.
lastUpdated: 2026-10-15T00:00:00.000Z
---

A new reactor starts from the first event in the event sequence and catches up on everything that is already there. That is what you want for a reactor that builds something from history. It is not what you want for one that sends an email, calls an external system or starts a job, because it will do that once for every event in history the moment it is deployed.

Mark such a reactor with `StartAtTail`. The first time Chronicle sees it, the reactor begins at the tail of the event sequence and observes only what is appended from then on.

**C#**

```csharp
using Cratis.Chronicle.Events;
using Cratis.Chronicle.Reactors;

[EventType]
public record WelcomeEmailRequested(string Email);

[StartAtTail]
public class SendWelcomeEmails : IReactor
{
    public Task Requested(WelcomeEmailRequested @event)
    {
        // Runs for events appended after this reactor was first registered.
        // It does not run for the history that was already in the event log.
        return Task.CompletedTask;
    }
}
```

[View C# snippet source on GitHub](https://github.com/Cratis/Chronicle/blob/main/Documentation/client-snippets/reactors/start-at-tail/basic.md)

**Kotlin**

```kotlin
import io.cratis.chronicle.events.EventType
import io.cratis.chronicle.observation.Reactor
import io.cratis.chronicle.observation.StartAtTail

@EventType
data class WelcomeEmailRequested(val email: String)

@Reactor
@StartAtTail
class SendWelcomeEmails {
    fun requested(event: WelcomeEmailRequested) {
        // Runs for events appended after this reactor was first registered.
        // It does not run for the history that was already in the event log.
    }
}
```

[View Kotlin snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets/reactors/start-at-tail/basic.md)

**Java**

```java
import io.cratis.chronicle.events.EventType;
import io.cratis.chronicle.observation.Reactor;
import io.cratis.chronicle.observation.StartAtTail;

@EventType
record WelcomeEmailRequested(String email) {}

@Reactor
@StartAtTail
class SendWelcomeEmails {
    void requested(WelcomeEmailRequested event) {
        // Runs for events appended after this reactor was first registered.
        // It does not run for the history that was already in the event log.
    }
}
```

[View Java snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets-java/reactors/start-at-tail/basic.md)

**Elixir**

```elixir
defmodule WelcomeEmailRequested do
  use Chronicle.Events.EventType, id: "welcome-email-requested"

  defstruct [:email]
end

defmodule SendWelcomeEmails do
  # Begin at the tail of the event sequence the first time this reactor is
  # registered, so it never acts on history that predates it.
  use Chronicle.Reactors.Reactor, start_at_tail: true

  @handles WelcomeEmailRequested

  @impl true
  def handle(%WelcomeEmailRequested{}, _context) do
    # Send the email.
    :ok
  end
end
```

[View Elixir snippet source on GitHub](https://github.com/Cratis/Chronicle.Elixir/blob/main/Documentation/client-snippets/reactors/start-at-tail/basic.md)

**TypeScript**

```typescript
import { eventType, reactor, startAtTail } from '@cratis/chronicle';
import { field } from '@cratis/fundamentals';

@eventType()
class WelcomeEmailRequested {
    @field(String) readonly email: string;

    constructor(email: string = '') {
        this.email = email;
    }
}

@reactor()
@startAtTail()
class SendWelcomeEmails {
    welcomeEmailRequested(event: WelcomeEmailRequested): void {
        // Runs for events appended after this reactor was first registered.
        // It does not run for the history that was already in the event log.
    }
}
```

[View TypeScript snippet source on GitHub](https://github.com/Cratis/Chronicle.TypeScript/blob/main/Documentation/client-snippets/reactors/start-at-tail/basic.md)

## What it does

`StartAtTail` decides where a reactor **starts**, once. It does not filter events and it does not change what the reactor does afterwards.

- **First registration only.** A reactor that Chronicle already holds a position for keeps that position. The marker is safe to leave in place; it never skips events after a restart or a redeploy.
- **Per namespace.** Each namespace has its own observer, so a reactor that appears in a new namespace starts at the tail of that namespace.
- **Replay is unaffected.** An explicit replay still replays from the beginning. See [Replay](/chronicle/reactors/replay/) and [OnceOnly](/chronicle/reactors/once-only/) for keeping side effects out of a replay.

## Compared with OnceOnly

`OnceOnly` and `StartAtTail` cover different moments, and a reactor with side effects often needs both:

| | Moment it acts on | What it does |
| --- | --- | --- |
| `OnceOnly` | A replay of an observer that already exists | Skips the handler for replayed events |
| `StartAtTail` | The first registration of a new observer | Starts at the tail, so history is never delivered |

Neither is an exactly-once guarantee. Recovering a failed partition re-delivers an event as ordinary observation. See [Delivery identity](/chronicle/reactors/delivery-identity/).

## Renaming a reactor

A reactor's default id is its full type name, so renaming it or moving its namespace makes it a **new** reactor, and a reactor marked `StartAtTail` starts at the tail again. That is usually the safe outcome. It also means events appended between the old reactor's last position and the rename are not seen by the new one. If the new reactor must continue from where the old one stopped, give it its old id explicitly. See [Reactor identity and renaming](/chronicle/reactors/identity/).

## Server and client versions

Both the Chronicle server and the client must support `StartAtTail`. A server that predates it ignores the request and the reactor catches up from the beginning, as before. Upgrade the server first, then the clients.
