Run Chronicle locally
Chronicle runs as a small kernel — a Docker image your application talks to over the network. Before a single line of your host code can append an event, that kernel has to be up and reachable. This is the one page that covers getting it there, so the console, worker service, and ASP.NET Core guides can all point here instead of repeating it.
You only need to do this once per machine. Leave it running in the background and come back to your code.
Prerequisites
Section titled “Prerequisites”- .NET 8 or higher — the SDK you build and run your app with.
- Docker Desktop or compatible — the kernel ships as a container.
- Optional: a MongoDB client such as MongoDB Compass, handy for peeking at the read models a projection builds. You don’t need it to follow the guides — the built-in workbench shows you the events.
The fastest start: the development image
Section titled “The fastest start: the development image”The latest-development image bundles MongoDB, so there’s nothing else to install or wire up — one command and the kernel is running:
docker run -d -p 27017:27017 -p 8080:8080 -p 35000:35000 cratis/chronicle:latest-developmentThree ports, three jobs:
| Port | What it is |
|---|---|
35000 | The kernel endpoint your app connects to (chronicle://localhost:35000). |
8080 | The Chronicle workbench — a web UI for browsing your event store. |
27017 | The bundled MongoDB, where projections write their read models. |
That’s everything most local work needs. If you’d rather run against a database you already have — or a different engine entirely — read on; otherwise skip to picking a host.
Bring your own database
Section titled “Bring your own database”The latest-development-slim image leaves the database out, so you point Chronicle at one you run yourself. Two environment variables tell it where to go:
Cratis__Chronicle__Storage__TypeCratis__Chronicle__Storage__ConnectionDetails
The Compose files below bring up the kernel and a database together. Pick the one for your engine.
MongoDB with Docker Compose
Section titled “MongoDB with Docker Compose”Chronicle uses MongoDB transactions and change streams, so MongoDB must run as a replica set (or a sharded cluster) — a standalone mongod won’t do. This file initializes a single-node replica set for local development:
services: chronicle: image: cratis/chronicle:latest-development-slim depends_on: - mongodb - mongodb-init environment: - Cratis__Chronicle__Storage__Type=MongoDB - Cratis__Chronicle__Storage__ConnectionDetails=mongodb://mongodb:27017/?directConnection=true ports: - 8080:8080 - 35000:35000
mongodb: image: mongo:8 command: ["mongod", "--replSet", "rs0", "--bind_ip_all"] ports: - 27017:27017
mongodb-init: image: mongo:8 depends_on: - mongodb restart: "no" command: - /bin/bash - -lc - | until mongosh --host mongodb --quiet --eval "db.adminCommand('ping')" >/dev/null 2>&1; do sleep 1 done mongosh --host mongodb --quiet --eval " try { rs.status(); } catch (e) { rs.initiate({ _id: 'rs0', members: [{ _id: 0, host: 'localhost:27017' }] }); }"Why this setup:
host: 'localhost:27017'makes the replica set topology usable from host tools (for examplemongoshand Compass) when they connect tomongodb://localhost:27017/?replicaSet=rs0.- Chronicle still reaches MongoDB over the Docker network (
mongodb:27017) and usesdirectConnection=trueto avoid following the advertised host back tolocalhostinside the Chronicle container. directConnection=truedoes not disable transactions; transactions still work because MongoDB is running as a replica set.- If your existing data volume was initialized with a different replica-set host, run
docker compose down -v(or wipe the MongoDB data volume) before starting again sors.initiate()can apply the new host.
PostgreSQL with Docker Compose
Section titled “PostgreSQL with Docker Compose”services: chronicle: image: cratis/chronicle:latest-development-slim depends_on: - postgres environment: - Cratis__Chronicle__Storage__Type=PostgreSql - Cratis__Chronicle__Storage__ConnectionDetails=Host=postgres;Port=5432;Database=chronicle;Username=postgres;Password=postgres ports: - 8080:8080 - 35000:35000
postgres: image: postgres:16 environment: - POSTGRES_DB=chronicle - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres ports: - 5432:5432SQL Server with Docker Compose
Section titled “SQL Server with Docker Compose”services: chronicle: image: cratis/chronicle:latest-development-slim depends_on: - sqlserver environment: - Cratis__Chronicle__Storage__Type=MsSql - Cratis__Chronicle__Storage__ConnectionDetails=Server=sqlserver,1433;Database=Chronicle;User Id=sa;Password=Your_strong_password123!;TrustServerCertificate=True;Encrypt=False ports: - 8080:8080 - 35000:35000
sqlserver: image: mcr.microsoft.com/mssql/server:2025-latest environment: - ACCEPT_EULA=Y - MSSQL_SA_PASSWORD=Your_strong_password123! ports: - 1433:1433SQLite with Docker Compose
Section titled “SQLite with Docker Compose”services: chronicle: image: cratis/chronicle:latest-development-slim environment: - Cratis__Chronicle__Storage__Type=Sqlite - Cratis__Chronicle__Storage__ConnectionDetails=Data Source=/data/chronicle.db volumes: - chronicle-data:/data ports: - 8080:8080 - 35000:35000
volumes: chronicle-data:Bring any of these up the usual way, in the background:
docker compose up -dOptional: add the Aspire dashboard
Section titled “Optional: add the Aspire dashboard”If you want local observability while developing — logs, traces, and metrics — run the kernel alongside the Aspire dashboard and set OTEL_EXPORTER_OTLP_ENDPOINT on the Chronicle container. Port 18888 is the dashboard UI in your browser; port 18889 is the OTLP receiver Chronicle exports to inside the Docker network:
services: chronicle: image: cratis/chronicle:latest-development environment: - OTEL_EXPORTER_OTLP_ENDPOINT=http://aspire-dashboard:18889 ports: - 27017:27017 - 8080:8080 - 11111:11111 - 30000:30000 - 35000:35000
aspire-dashboard: image: mcr.microsoft.com/dotnet/aspire-dashboard:latest environment: - DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS=true - ALLOW_UNSECURED_TRANSPORT=true - DOTNET_ENVIRONMENT=Development ports: - 18888:18888See it in the workbench
Section titled “See it in the workbench”Whichever image you ran, it includes the Chronicle workbench — a web UI for poking at your event store. Open http://localhost:8080, pick an event store, and look at Sequences to watch events land in order. It’s the quickest way to confirm the kernel is up and your app is actually appending.
Next: pick your host
Section titled “Next: pick your host”The kernel is running and listening on chronicle://localhost:35000. Now connect your app to it:
- Just exploring? The Get started quickstart scaffolds a ready-to-run app from a template — the fastest way to see the whole loop.
- Console — the bare-bones version, no DI container, every connection explicit.
- Worker service — a background host for the reacting side of an event-sourced system.
- ASP.NET Core — a web API that appends events straight from its endpoints.