Skip to content

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.)

Every client setting can be supplied three ways, and they layer in this order — later wins:

  1. appsettings.json, under the Cratis:Chronicle section — the usual home for the connection string and most settings.
  2. Environment variables, with the Cratis__Chronicle__ prefix (.NET maps the __ separator onto nested keys) — convenient for containers and CI.
  3. Code, via the configureOptions callback on AddCratisChronicle — 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");
}
}

View C# snippet source on GitHub

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.

  • ChronicleOptions Reference - Complete reference for all ChronicleOptions, ChronicleClientOptions, and ChronicleAspNetCoreOptions settings, including appsettings.json binding.
  • 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 ChronicleClient constructor parameters or IChronicleBuilder.
  • TLS - Configure client-side TLS options and certificate handling.

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;
}
}
}

View C# snippet source on GitHub

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.

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();
}
}
}

View C# snippet source on GitHub

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.

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.