Chronicle Elixir Client

Event sourcing for Elixir — the idiomatic client for Cratis Chronicle, the open-source (MIT) event-sourcing database and processing runtime.

Hex.pm Hex Docs License: MIT

Overview

cratis_chronicle brings event sourcing and CQRS to Elixir applications: append events to an event store, project them into read models, and react to them — all backed by the Chronicle Kernel. It builds on Chronicle's language-agnostic gRPC API and exposes OTP-native constructs including:

We believe event sourcing is worth it for almost any system dealing with information and business flows — and that in Elixir it should feel like Elixir: modules, structs, and use macros rather than a foreign paradigm. The client is designed to keep friction and boilerplate low, so it reads as familiar code even if you have never event-sourced before. It is part of one deliberately simple Cratis ecosystem, built with productivity, quality, and reliability in mind — AI-friendly by design, with free AI skills for building with the stack.

Install

Add cratis_chronicle to your mix.exs dependencies:

defp deps do
[
{:cratis_chronicle, "~> 3.5"}
]
end

The client needs Elixir 1.18 or later (googleapis requires 1.18). It uses grpc ~> 1.0, Mint 1.11 or later, and contracts 19.19 or later. CI builds and tests with Elixir 1.19.5 on Erlang/OTP 28.5. If your application also connects to gRPC independently, explicitly pass adapter: GRPC.Client.Adapters.Mint to GRPC.Stub.connect/2 (or add Gun as a direct dependency); grpc 1.x no longer requires you to supervise GRPC.Client.Supervisor. Chronicle disables Mint server push; if your application sets config :grpc, GRPC.Client.Adapters.Mint, client_settings: [...], it must include enable_push: false or the client rejects connection startup.

Prerequisite: Chronicle running

You need a Chronicle kernel before running samples or application code. For local development, pull and run the development image, which bundles MongoDB:

docker pull cratis/chronicle:latest-development
docker run -d --name chronicle \
-p 127.0.0.1:35000:35000 \
-p 127.0.0.1:27017:27017 \
cratis/chronicle:latest-development

The 127.0.0.1: prefixes keep both ports on your machine: the development kernel accepts well-known credentials and its MongoDB has no authentication. Pull before you run, because the kernel must understand the cratis_chronicle_contracts version that mix deps.get resolves.

Getting started

Get started with the Elixir client walks through installation, connecting, appending an event and reading a read model, including the failure results to expect along the way. The published documentation is at cratis.io, and the API reference is on HexDocs.

Quick example

defmodule MyApp.Events.AccountOpened do
use Chronicle.Events.EventType, id: "account-opened"
# Typed defaults: the client derives the event's JSON schema from them.
defstruct owner: "", balance: 0
end
defmodule MyApp.ReadModels.Account do
use Chronicle.ReadModels.ReadModel
defstruct id: "", owner: "", balance: 0
# owner and balance are mapped by name; id comes from the event source id.
from MyApp.Events.AccountOpened, set: [id: :event_source_id]
end
defmodule MyApp.Application do
use Application
@impl true
def start(_type, _args) do
children = [
{Chronicle.Client,
# Development-only credentials for the local development kernel.
connection_string: "chronicle://chronicle-dev-client:chronicle-dev-secret@localhost:35000",
event_store: "my-app",
otp_app: :my_app}
]
Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
end
end

Then, with the application running (for example in iex -S mix):

alias Chronicle.Connections.Lifecycle
# The client connects and registers in the background; until then, calls return
# {:error, :not_connected}.
:ok = Lifecycle.wait_until(Lifecycle.name_for(Chronicle.Client), :registered)
:ok = Chronicle.append("account-42", %MyApp.Events.AccountOpened{owner: "Alice", balance: 1000})
# Projections run asynchronously: this can be {:ok, nil} until the projection catches up.
{:ok, account} = Chronicle.read_model(MyApp.ReadModels.Account, "account-42")

Known limitations

The Elixir client documentation explains each one.

Structure

Source/
chronicle/ ← cratis_chronicle Hex package
Documentation/ ← Elixir client documentation and client-owned snippets
Samples/
console/ ← Runnable interactive console sample

Building

cd Source/chronicle
mix deps.get
mix compile
mix test

Running the console sample

A working example is in the Samples/console directory. It uses the client from Source/chronicle and starts its own kernel with Docker Compose; see its README for controls and details.

cd Samples/console
docker compose up -d
mix deps.get
mix run --no-halt

Set CHRONICLE_CONNECTION_STRING to connect to another kernel:

CHRONICLE_CONNECTION_STRING="chronicle://client-id:client-secret@myserver:35000?skipTlsValidation=false" mix run --no-halt

The Cratis ecosystem

This project is part of Cratis — free, MIT-licensed tools for building event-sourced and CQRS applications.

Everything Cratis publishes today is MIT licensed and free to use.