Configuration
Chronicle always runs as a separate process — the kernel — and your application talks to it as a client over gRPC. There is no in-process or embedded kernel to host inside your app, so on this side you’re configuring how your application connects and behaves as a client. (To configure the kernel itself — ports, storage backends, features — see Hosting Configuration.)
How client configuration flows
Section titled “How client configuration flows”Every client setting can be supplied three ways, and they layer in this order — later wins:
appsettings.json, under theCratis:Chroniclesection — the usual home for the connection string and most settings.- Environment variables, with the
Cratis__Chronicle__prefix (.NET maps the__separator onto nested keys) — convenient for containers and CI. - Code, via the
configureOptionscallback onAddCratisChronicle— it runs after binding, so it overrides configuration. Structural dependencies (custom resolvers and providers) can only be set here.
A minimal appsettings.json:
{ "Cratis": { "Chronicle": { "ConnectionString": "chronicle://localhost:35000", "EventStore": "my-store" } }}The matching registration on the host — AddCratisChronicle reads the section above, and the callback overrides it:
using Microsoft.Extensions.Hosting;
public static class ConfigurationIndexRegistration{ public static void Configure(string[] args) { var builder = Host.CreateApplicationBuilder(args);
builder.AddCratisChronicle(options => options.EventStore = "my-store"); }}import io.cratis.chronicle.ChronicleClientimport io.cratis.chronicle.ChronicleOptionsimport io.cratis.chronicle.EventStoreimport io.cratis.chronicle.connection.ChronicleConnectionString
fun registerEventStore(): EventStore { val options = ChronicleOptions(connectionString = ChronicleConnectionString.DEVELOPMENT) val client = ChronicleClient(options) return client.getEventStore("my-store")}import io.cratis.chronicle.ChronicleOptions;import io.cratis.chronicle.java.BlockingEventStore;import io.cratis.chronicle.java.BlockingChronicleClient;
class ConfigurationIndexRegister { BlockingEventStore create() { BlockingChronicleClient client = BlockingChronicleClient.connect(ChronicleOptions.development()); return client.getEventStore("my-store"); }}defmodule MyApp.ConfigurationIndexRegistration do @moduledoc false
def start_link do children = [ {Chronicle.Client, event_store: "my-store"} ]
Supervisor.start_link(children, strategy: :one_for_one) endendimport { ChronicleClient, ChronicleOptions } from '@cratis/chronicle';
async function runConfigurationIndexRegistrationExample(): Promise<void> { const client = new ChronicleClient(ChronicleOptions.fromConnectionString('chronicle://localhost:35000')); const eventStore = await client.getEventStore('my-store');}AddCratisChronicle is an extension on the host builder — IHostApplicationBuilder for worker and console hosts, WebApplicationBuilder for ASP.NET Core. See the getting-started host guides for the full setup of each.
Topics
Section titled “Topics”- ChronicleOptions Reference - Complete reference for all
ChronicleOptions,ChronicleClientOptions, andChronicleAspNetCoreOptionssettings, includingappsettings.jsonbinding. - Connection Strings - The
chronicle://connection string format, development defaults, and credentials. - Namespaces - Resolve the event store namespace per request — the basis of multi-tenancy.
- Camel Casing - Configure camel case naming policy for projection definitions and read model persistence.
- gRPC Message Size - Configure maximum gRPC message sizes for large event batches.
- Structural Dependencies - Configure artifact discovery, identity, namespace resolution, and other build-time dependencies via
ChronicleClientconstructor parameters orIChronicleBuilder. - TLS - Configure client-side TLS options and certificate handling.
Explicit artifacts
Section titled “Explicit artifacts”Nominate artifacts in code when their assemblies cannot carry Chronicle markers or when you want composition-root registration. Existing markers remain supported; explicit declarations merge with them rather than overriding conflicting identities.
using Cratis.Chronicle;using Cratis.Chronicle.Events.Constraints;
namespace ExplicitCompositionExample{ public record OrderPlaced(decimal Total); public record OrderTotal(decimal Total);
public class TotalReducer { public OrderTotal Reduce(OrderPlaced @event, OrderTotal? current) => new((current?.Total ?? 0m) + @event.Total); }
public class OrderNotifier { public void On(OrderPlaced @event) => Console.WriteLine($"Order total: {@event.Total}"); }
public class OneOrderPerSource { public void Define(IConstraintBuilder builder) => builder.Unique<OrderPlaced>(); }
public class Customers;
public static class Composition { public static ChronicleOptions CreateOptions() { var options = new ChronicleOptions(); options.ExplicitArtifacts .RegisterEventType<OrderPlaced>(_ => _.WithId("order-placed").Public()) .RegisterReactor<OrderNotifier>("order-notifier") .RegisterReducer<TotalReducer>("order-total") .RegisterConstraint<OneOrderPerSource>() .RegisterEventSource<Customers>("customers"); return options; } }}Configure the options before creating stores. Each store captures an immutable snapshot; later options edits do not alter existing stores or their reconnect registrations. See the .NET API reference for event facets, conflict rules, plain observer shapes and custom-provider compatibility.
Registry-resolved concurrency
Section titled “Registry-resolved concurrency”An explicit alias belongs to the store’s registry, not the CLR type’s attributes. Resolve the identity from that registry before constructing a concurrency scope:
using Cratis.Chronicle;using Cratis.Chronicle.Events;using Cratis.Chronicle.EventSequences.Concurrency;
namespace ExplicitConcurrencyExample{ public record OrderPlaced(decimal Total);
public static class Scope { public static ConcurrencyScope ForOrder(IEventStore store, EventSourceId source) { var eventType = store.EventTypes.GetEventTypeFor(typeof(OrderPlaced)); return new ConcurrencyScopeBuilder() .WithEventSourceId(source) .WithEventType(eventType) .Build(); } }}The scope uses the registered id and generation, including aliases, through the existing builder APIs. Declaration-only Type/generic helpers retain their marker-based behavior.
Configuring the server
Section titled “Configuring the server”The kernel is configured separately from the client. See Hosting Configuration for the chronicle.json file, environment variables, storage backends, and ports. To stand the kernel up locally, see Run Chronicle locally.