---
title: Structural Dependencies
editUrl: https://github.com/Cratis/Chronicle/edit/main/Documentation/configuration/structural-dependencies.mdx
description: Supply custom resolvers and providers to the .NET client, and how they differ from options bound from configuration.
---

import { Tabs, TabItem } from '@astrojs/starlight/components';


`ChronicleOptions` is designed to hold **runtime configuration** that can be bound from `appsettings.json` or environment variables — connection strings, timeouts, TLS settings, naming policies, and so on.

Services and providers that must be resolved at registration time (before the DI container is built) are called **structural dependencies**. These are not configuration values and cannot be meaningfully bound from `appsettings.json`. They are passed directly as constructor arguments to `ChronicleClient` or set on `IChronicleBuilder` when using the DI-hosted setup (`IHostApplicationBuilder`, `WebApplicationBuilder`).

## Structural dependencies

| Dependency | Purpose | Default |
| --- | --- | --- |
| `IClientArtifactsProvider` | Discovers event types, projections, reactors, reducers, and other artifacts at startup | `DefaultClientArtifactsProvider` (auto-discovers from loaded assemblies) |
| `IIdentityProvider` | Supplies the current user's identity for event metadata | `BaseIdentityProvider` (empty identity) |
| `ICorrelationIdAccessor` | Provides the current correlation ID for event metadata | `CorrelationIdAccessor` (generates a new ID per call) |
| `IEventStoreNamespaceResolver` | Resolves the event store namespace for each operation | `DefaultEventStoreNamespaceResolver` (always returns the default namespace) |
| `ILoggerFactory` | Creates loggers for the Chronicle client internals | `LoggerFactory` (no-op) |

## Passing to ChronicleClient directly

For console applications or other non-DI scenarios, pass structural dependencies as named constructor parameters:

<Tabs syncKey="chronicle-client">
<TabItem label="C#">

```csharp
using Microsoft.Extensions.Logging;

public static class StructuralDependenciesDirectClient
{
    public static ChronicleClient Create(ChronicleOptions options, IClientArtifactsProvider myProvider) =>
        new(
            options,
            artifactsProvider: myProvider,
            loggerFactory: LoggerFactory.Create(b => b.AddConsole()));
}
```

[View C# snippet source on GitHub](https://github.com/Cratis/Chronicle/blob/main/Documentation/client-snippets/configuration/structural-dependencies/direct-client.md)

</TabItem>
<TabItem label="Kotlin">

```kotlin
import io.cratis.chronicle.ChronicleClient
import io.cratis.chronicle.ChronicleOptions
import io.cratis.chronicle.artifacts.IArtifactActivator
import io.cratis.chronicle.artifacts.IClientArtifacts
import io.cratis.chronicle.connection.ChronicleConnectionString

/**
 * Unlike the .NET client, structural dependencies are not separate constructor parameters on
 * [ChronicleClient] — they are carried on [ChronicleOptions] itself, which is where every named
 * dependency below actually lives.
 */
fun createClient(artifacts: IClientArtifacts, artifactActivator: IArtifactActivator): ChronicleClient {
    val options = ChronicleOptions(
        connectionString = ChronicleConnectionString.DEVELOPMENT,
        artifacts = artifacts,
        artifactActivator = artifactActivator
    )
    return ChronicleClient(options)
}
```

[View Kotlin snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets/configuration/structural-dependencies/direct-client.md)

</TabItem>
<TabItem label="Java">

```java
import io.cratis.chronicle.ChronicleOptions;
import io.cratis.chronicle.artifacts.IArtifactActivator;
import io.cratis.chronicle.artifacts.IClientArtifacts;
import io.cratis.chronicle.connection.ChronicleConnectionString;
import io.cratis.chronicle.java.BlockingChronicleClient;

// Unlike the .NET client, structural dependencies are not separate constructor parameters on the
// client — they are carried on ChronicleOptions itself, which is where every named dependency
// below actually lives.
class StructuralDependenciesDirectClient {
    BlockingChronicleClient create(IClientArtifacts artifacts, IArtifactActivator artifactActivator) {
        ChronicleOptions options = new ChronicleOptions(
            ChronicleConnectionString.Companion.getDEVELOPMENT(),
            "Unknown",
            io.cratis.chronicle.sinks.WellKnownSinkTypes.MONGODB,
            true,
            artifacts,
            artifactActivator);
        return BlockingChronicleClient.connect(options);
    }
}
```

[View Java snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets-java/configuration/structural-dependencies/direct-client.md)

</TabItem>
<TabItem label="Elixir">

```text
Elixir does not support this workflow yet.
```

[View Elixir snippet source on GitHub](https://github.com/Cratis/Chronicle.Elixir/blob/main/Documentation/client-snippets/configuration/structural-dependencies/direct-client.md)

</TabItem>
<TabItem label="TypeScript">

```text
TypeScript does not support this workflow yet.
```

[View TypeScript snippet source on GitHub](https://github.com/Cratis/Chronicle.TypeScript/blob/main/Documentation/client-snippets/configuration/structural-dependencies/direct-client.md)

</TabItem>
</Tabs>

All parameters are optional. Any parameter you omit uses the default shown in the table above.

## Configuring with IChronicleBuilder

In DI-hosted applications (ASP.NET Core, worker services, or any `IHostApplicationBuilder`-based host), use the `configure` callback on `AddCratisChronicle` to set structural dependencies via the `IChronicleBuilder` fluent API. This callback runs at registration time, before the DI container is built.

<Tabs syncKey="chronicle-client">
<TabItem label="C#">

```csharp
using Cratis.Chronicle.Identities;
using Microsoft.Extensions.Hosting;

public static class StructuralDependenciesChronicleBuilderRegistration
{
    public static void Configure(string[] args, IClientArtifactsProvider myCustomProvider, IIdentityProvider myIdentityProvider)
    {
        var builder = Host.CreateApplicationBuilder(args);

        builder.AddCratisChronicle(
            configureOptions: options =>                         // runtime config — bindable from appsettings.json
            {
                options.EventStore = "my-store";
                options.ConnectionString = "chronicle://server:35000";
            },
            configure: b => b                                    // structural dependencies
                .WithArtifactsProvider(myCustomProvider)
                .WithIdentityProvider(myIdentityProvider));
    }
}
```

[View C# snippet source on GitHub](https://github.com/Cratis/Chronicle/blob/main/Documentation/client-snippets/configuration/structural-dependencies/chronicle-builder.md)

</TabItem>
<TabItem label="Kotlin">

```text
Kotlin does not support this workflow yet.
```

[View Kotlin snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets/configuration/structural-dependencies/chronicle-builder.md)

</TabItem>
<TabItem label="Java">

```text
Java does not support this workflow yet.
```

[View Java snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets-java/configuration/structural-dependencies/chronicle-builder.md)

</TabItem>
<TabItem label="Elixir">

```text
Elixir does not support this workflow yet.
```

[View Elixir snippet source on GitHub](https://github.com/Cratis/Chronicle.Elixir/blob/main/Documentation/client-snippets/configuration/structural-dependencies/chronicle-builder.md)

</TabItem>
<TabItem label="TypeScript">

```text
TypeScript does not support this workflow yet.
```

[View TypeScript snippet source on GitHub](https://github.com/Cratis/Chronicle.TypeScript/blob/main/Documentation/client-snippets/configuration/structural-dependencies/chronicle-builder.md)

</TabItem>
</Tabs>

The same pattern works with `WebApplicationBuilder` in ASP.NET Core:

<Tabs syncKey="chronicle-client">
<TabItem label="C#">

```csharp
using Cratis.Chronicle.Identities;
using Microsoft.AspNetCore.Builder;

public static class StructuralDependenciesAspNetCoreBuilderRegistration
{
    public static void Configure(string[] args, IIdentityProvider myIdentityProvider)
    {
        // ASP.NET Core — WebApplicationBuilder
        var builder = WebApplication.CreateBuilder(args);
        builder.AddCratisChronicle(
            configureOptions: options => options.EventStore = "my-store",
            configure: b => b
                .WithIdentityProvider(myIdentityProvider));
    }
}
```

[View C# snippet source on GitHub](https://github.com/Cratis/Chronicle/blob/main/Documentation/client-snippets/configuration/structural-dependencies/aspnetcore-builder.md)

</TabItem>
<TabItem label="Kotlin">

```text
Kotlin does not support this workflow yet.
```

[View Kotlin snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets/configuration/structural-dependencies/aspnetcore-builder.md)

</TabItem>
<TabItem label="Java">

```text
Java does not support this workflow yet.
```

[View Java snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets-java/configuration/structural-dependencies/aspnetcore-builder.md)

</TabItem>
<TabItem label="Elixir">

```text
Elixir does not support this workflow yet.
```

[View Elixir snippet source on GitHub](https://github.com/Cratis/Chronicle.Elixir/blob/main/Documentation/client-snippets/configuration/structural-dependencies/aspnetcore-builder.md)

</TabItem>
<TabItem label="TypeScript">

```text
TypeScript does not support this workflow yet.
```

[View TypeScript snippet source on GitHub](https://github.com/Cratis/Chronicle.TypeScript/blob/main/Documentation/client-snippets/configuration/structural-dependencies/aspnetcore-builder.md)

</TabItem>
</Tabs>

The two callbacks are intentionally separate:
- `configureOptions` feeds the options pipeline. It runs after `appsettings.json` and `IConfiguration` are bound, so a value it sets overrides the configured one.
- `configure` sets structural dependencies at registration time and is not overridable by configuration.

## IChronicleBuilder fluent methods

| Method | Sets |
| --- | --- |
| `WithArtifactsProvider(IClientArtifactsProvider)` | Custom artifact discovery |
| `WithIdentityProvider(IIdentityProvider)` | Custom identity resolution |
| `WithCorrelationIdAccessor(ICorrelationIdAccessor)` | Custom correlation ID accessor |
| `WithNamespaceResolver(IEventStoreNamespaceResolver)` | Custom namespace resolution |

## Custom artifact discovery

Implement `IClientArtifactsProvider` when you need to control exactly which types Chronicle discovers. This is useful in modular applications or when using assembly scanning that differs from the default:

<Tabs syncKey="chronicle-client">
<TabItem label="C#">

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

[EventType]
public record StructuralDepsBookBorrowed(string BookId);

[EventType]
public record StructuralDepsBookReturned(string BookId);

public record StructuralDepsBorrowedBook(string BookId);

public class StructuralDepsBorrowedBooksProjection : IProjectionFor<StructuralDepsBorrowedBook>
{
    public void Define(IProjectionBuilderFor<StructuralDepsBorrowedBook> builder) => builder
        .From<StructuralDepsBookBorrowed>();
}

public class StructuralDepsMyArtifactsProvider : IClientArtifactsProvider
{
    public IEnumerable<Type> EventTypes => [typeof(StructuralDepsBookBorrowed), typeof(StructuralDepsBookReturned)];
    public IEnumerable<Type> Projections => [typeof(StructuralDepsBorrowedBooksProjection)];
    public IEnumerable<Type> ModelBoundProjections => [];
    public IEnumerable<Type> Reactors => [];
    public IEnumerable<Type> ReadModelReactors => [];
    public IEnumerable<Type> Reducers => [];
    public IEnumerable<Type> ReactorMiddlewares => [];
    public IEnumerable<Type> ComplianceForTypesProviders => [];
    public IEnumerable<Type> ComplianceForPropertiesProviders => [];
    public IEnumerable<Type> AdditionalEventInformationProviders => [];
    public IEnumerable<Type> ConstraintTypes => [];
    public IEnumerable<Type> UniqueConstraints => [];
    public IEnumerable<Type> UniqueEventTypeConstraints => [];
    public IEnumerable<Type> RemoveConstraintEventTypes => [];
    public IEnumerable<Type> EventTypeMigrators => [];
    public IEnumerable<Type> EventSeeders => [];
}
```

[View C# snippet source on GitHub](https://github.com/Cratis/Chronicle/blob/main/Documentation/client-snippets/configuration/structural-dependencies/custom-artifacts-provider.md)

</TabItem>
<TabItem label="Kotlin">

```kotlin
import io.cratis.chronicle.artifacts.IClientArtifacts
import io.cratis.chronicle.events.EventType
import io.cratis.chronicle.projections.IProjectionFor
import io.cratis.chronicle.projections.IProjectionBuilderFor
import io.cratis.chronicle.readModels.ReadModel
import kotlin.reflect.KClass

@EventType
data class StructuralDepsBookBorrowed(val bookId: String = "")

@EventType
data class StructuralDepsBookReturned(val bookId: String = "")

@ReadModel
data class StructuralDepsBorrowedBook(val bookId: String = "")

class StructuralDepsBorrowedBooksProjection : IProjectionFor<StructuralDepsBorrowedBook> {
    override fun define(builder: IProjectionBuilderFor<StructuralDepsBorrowedBook>) {
        builder.from(StructuralDepsBookBorrowed::class) {
            it.set(StructuralDepsBorrowedBook::bookId).toProperty("bookId")
        }
    }
}

class StructuralDepsMyArtifacts : IClientArtifacts {
    override val eventTypes: List<KClass<*>> = listOf(StructuralDepsBookBorrowed::class, StructuralDepsBookReturned::class)
    override val eventTypeMigrations: List<KClass<*>> = emptyList()
    override val readModels: List<KClass<*>> = listOf(StructuralDepsBorrowedBook::class)
    override val projections: List<KClass<*>> = listOf(StructuralDepsBorrowedBooksProjection::class)
    override val modelBoundProjections: List<KClass<*>> = emptyList()
    override val reactors: List<KClass<*>> = emptyList()
    override val reducers: List<KClass<*>> = emptyList()
    override val constraints: List<KClass<*>> = emptyList()
    override val eventSeeders: List<KClass<*>> = emptyList()
    override val webhooks: List<KClass<*>> = emptyList()
    override val captures: List<KClass<*>> = emptyList()
    override val reactorMiddlewares: List<KClass<*>> = emptyList()
    override val reactorArgumentResolvers: List<KClass<*>> = emptyList()
}
```

[View Kotlin snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets/configuration/structural-dependencies/custom-artifacts-provider.md)

</TabItem>
<TabItem label="Java">

```java
import io.cratis.chronicle.artifacts.IClientArtifacts;
import io.cratis.chronicle.events.EventType;
import io.cratis.chronicle.projections.IProjectionBuilderFor;
import io.cratis.chronicle.projections.IProjectionFor;
import io.cratis.chronicle.readModels.ReadModel;
import io.cratis.chronicle.java.ProjectionBuilderJavaBridge;

import java.util.Collections;
import java.util.List;

import kotlin.reflect.KClass;
import kotlin.jvm.JvmClassMappingKt;

@EventType
record StructuralDepsBookBorrowed(String bookId) {}

@EventType
record StructuralDepsBookReturned(String bookId) {}

@ReadModel
class StructuralDepsBorrowedBook {
    public String bookId = "";
}

class StructuralDepsBorrowedBooksProjection implements IProjectionFor<StructuralDepsBorrowedBook> {
    @Override
    public void define(IProjectionBuilderFor<StructuralDepsBorrowedBook> builder) {
        // AutoMap matches StructuralDepsBookBorrowed.bookId to StructuralDepsBorrowedBook.bookId by name.
        ProjectionBuilderJavaBridge.from(builder, StructuralDepsBookBorrowed.class);
    }
}

class StructuralDepsMyArtifacts implements IClientArtifacts {
    private static KClass<?> kotlin(Class<?> type) {
        return JvmClassMappingKt.getKotlinClass(type);
    }

    @Override
    public List<KClass<?>> getEventTypes() {
        return List.of(kotlin(StructuralDepsBookBorrowed.class), kotlin(StructuralDepsBookReturned.class));
    }

    @Override
    public List<KClass<?>> getEventTypeMigrations() { return Collections.emptyList(); }

    @Override
    public List<KClass<?>> getReadModels() { return List.of(kotlin(StructuralDepsBorrowedBook.class)); }

    @Override
    public List<KClass<?>> getProjections() { return List.of(kotlin(StructuralDepsBorrowedBooksProjection.class)); }

    @Override
    public List<KClass<?>> getModelBoundProjections() { return Collections.emptyList(); }

    @Override
    public List<KClass<?>> getReactors() { return Collections.emptyList(); }

    @Override
    public List<KClass<?>> getReducers() { return Collections.emptyList(); }

    @Override
    public List<KClass<?>> getConstraints() { return Collections.emptyList(); }

    @Override
    public List<KClass<?>> getEventSeeders() { return Collections.emptyList(); }

    @Override
    public List<KClass<?>> getWebhooks() { return Collections.emptyList(); }

    @Override
    public List<KClass<?>> getCaptures() { return Collections.emptyList(); }

    @Override
    public List<KClass<?>> getReactorMiddlewares() { return Collections.emptyList(); }

    @Override
    public List<KClass<?>> getReactorArgumentResolvers() { return Collections.emptyList(); }
}
```

[View Java snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets-java/configuration/structural-dependencies/custom-artifacts-provider.md)

</TabItem>
<TabItem label="Elixir">

```text
Elixir does not support this workflow yet.
```

[View Elixir snippet source on GitHub](https://github.com/Cratis/Chronicle.Elixir/blob/main/Documentation/client-snippets/configuration/structural-dependencies/custom-artifacts-provider.md)

</TabItem>
<TabItem label="TypeScript">

```typescript
import { field, Constructor } from '@cratis/fundamentals';
import { eventType, IClientArtifactsProvider, IProjectionBuilderFor, IProjectionFor, projection } from '@cratis/chronicle';

@eventType()
class StructuralDepsBookBorrowed {
    @field(String) readonly bookId: string;

    constructor(bookId: string) {
        this.bookId = bookId;
    }
}

@eventType()
class StructuralDepsBookReturned {
    @field(String) readonly bookId: string;

    constructor(bookId: string) {
        this.bookId = bookId;
    }
}

class StructuralDepsBorrowedBook {
    bookId = '';
}

@projection()
class StructuralDepsBorrowedBooksProjection implements IProjectionFor<StructuralDepsBorrowedBook> {
    define(builder: IProjectionBuilderFor<StructuralDepsBorrowedBook>): void {
        builder.from(StructuralDepsBookBorrowed, _ => _
            .set(m => m.bookId).to(e => e.bookId));
    }
}

class StructuralDepsMyArtifactsProvider implements IClientArtifactsProvider {
    readonly eventTypes: Constructor[] = [StructuralDepsBookBorrowed, StructuralDepsBookReturned];
    readonly readModels: Constructor[] = [];
    readonly reactors: Constructor[] = [];
    readonly reducers: Constructor[] = [];
    readonly seeders: Constructor[] = [];
    readonly constraints: Constructor[] = [];
    readonly projections: Constructor[] = [StructuralDepsBorrowedBooksProjection];
    readonly webhooks: Constructor[] = [];
    readonly eventTypeMigrations: Constructor[] = [];
    readonly globalForHandlers: Constructor[] = [];
}
```

[View TypeScript snippet source on GitHub](https://github.com/Cratis/Chronicle.TypeScript/blob/main/Documentation/client-snippets/configuration/structural-dependencies/custom-artifacts-provider.md)

</TabItem>
</Tabs>

<Tabs syncKey="chronicle-client">
<TabItem label="C#">

```csharp
using Microsoft.Extensions.Hosting;

public static class StructuralDepsCustomArtifactsProviderUsageRegistration
{
    public static void Configure(string[] args)
    {
        var builder = Host.CreateApplicationBuilder(args);

        builder.AddCratisChronicle(
            configureOptions: options => options.EventStore = "my-store",
            configure: b => b.WithArtifactsProvider(new StructuralDepsMyArtifactsProvider()));
    }
}
```

[View C# snippet source on GitHub](https://github.com/Cratis/Chronicle/blob/main/Documentation/client-snippets/configuration/structural-dependencies/custom-artifacts-provider-usage.md)

</TabItem>
<TabItem label="Kotlin">

```kotlin
import io.cratis.chronicle.ChronicleOptions
import io.cratis.chronicle.connection.ChronicleConnectionString

fun optionsWithCustomArtifacts(): ChronicleOptions = ChronicleOptions(
    connectionString = ChronicleConnectionString.DEVELOPMENT,
    artifacts = StructuralDepsMyArtifacts()
)
```

[View Kotlin snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets/configuration/structural-dependencies/custom-artifacts-provider-usage.md)

</TabItem>
<TabItem label="Java">

```java
import io.cratis.chronicle.ChronicleOptions;
import io.cratis.chronicle.connection.ChronicleConnectionString;

class StructuralDepsCustomArtifactsProviderUsage {
    ChronicleOptions create() {
        return new ChronicleOptions(
            ChronicleConnectionString.Companion.getDEVELOPMENT(),
            "Unknown",
            io.cratis.chronicle.sinks.WellKnownSinkTypes.MONGODB,
            true,
            new StructuralDepsMyArtifacts());
    }
}
```

[View Java snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets-java/configuration/structural-dependencies/custom-artifacts-provider-usage.md)

</TabItem>
<TabItem label="Elixir">

```text
Elixir does not support this workflow yet.
```

[View Elixir snippet source on GitHub](https://github.com/Cratis/Chronicle.Elixir/blob/main/Documentation/client-snippets/configuration/structural-dependencies/custom-artifacts-provider-usage.md)

</TabItem>
<TabItem label="TypeScript">

```typescript
import { ChronicleOptions } from '@cratis/chronicle';

function createStructuralDependenciesCustomArtifactsProviderOptions(): ChronicleOptions {
    return ChronicleOptions.fromConnectionString('chronicle://localhost:35000', {
        clientArtifactsProvider: new StructuralDepsMyArtifactsProvider()
    });
}
```

[View TypeScript snippet source on GitHub](https://github.com/Cratis/Chronicle.TypeScript/blob/main/Documentation/client-snippets/configuration/structural-dependencies/custom-artifacts-provider-usage.md)

</TabItem>
</Tabs>

## DefaultClientArtifactsProvider

`DefaultClientArtifactsProvider` scans loaded assemblies for artifacts at first access (lazy initialization). You can construct it with a custom assembly provider:

<Tabs syncKey="chronicle-client">
<TabItem label="C#">

```csharp
using Cratis.Types;

public static class StructuralDepsDefaultArtifactsProvider
{
    public static DefaultClientArtifactsProvider Create()
    {
        var assembliesProvider = new CompositeAssemblyProvider(
            ProjectReferencedAssemblies.Instance,
            PackageReferencedAssemblies.Instance);

        return new DefaultClientArtifactsProvider(assembliesProvider);
    }
}
```

[View C# snippet source on GitHub](https://github.com/Cratis/Chronicle/blob/main/Documentation/client-snippets/configuration/structural-dependencies/default-artifacts-provider.md)

</TabItem>
<TabItem label="Kotlin">

```kotlin
import io.cratis.chronicle.artifacts.ClientArtifacts
import io.cratis.chronicle.artifacts.IClientArtifacts

// Scans only the given packages and everything beneath them, instead of the whole classpath.
fun scopedArtifacts(): IClientArtifacts = ClientArtifacts("com.acme.ordering", "com.acme.shipping")

// The classpath-wide instance used when no artifacts are configured, shared across every event
// store in the process so the classpath is scanned at most once.
fun defaultArtifacts(): IClientArtifacts = ClientArtifacts.default
```

[View Kotlin snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets/configuration/structural-dependencies/default-artifacts-provider.md)

</TabItem>
<TabItem label="Java">

```java
import io.cratis.chronicle.artifacts.ClientArtifacts;
import io.cratis.chronicle.artifacts.IClientArtifacts;

class StructuralDepsDefaultArtifactsProvider {
    // Scans only the given packages and everything beneath them, instead of the whole classpath.
    ClientArtifacts create() {
        return new ClientArtifacts("com.acme.ordering", "com.acme.shipping");
    }

    // The classpath-wide instance used when no artifacts are configured, shared across every
    // event store in the process so the classpath is scanned at most once.
    IClientArtifacts getDefault() {
        return ClientArtifacts.Companion.getDefault();
    }
}
```

[View Java snippet source on GitHub](https://github.com/Cratis/Chronicle.Kotlin/blob/main/Documentation/client-snippets-java/configuration/structural-dependencies/default-artifacts-provider.md)

</TabItem>
<TabItem label="Elixir">

```text
Elixir does not support this workflow yet.
```

[View Elixir snippet source on GitHub](https://github.com/Cratis/Chronicle.Elixir/blob/main/Documentation/client-snippets/configuration/structural-dependencies/default-artifacts-provider.md)

</TabItem>
<TabItem label="TypeScript">

```typescript
import { DefaultClientArtifactsProvider, TypeDiscoverer } from '@cratis/chronicle';

// TypeScript artifacts register with TypeDiscoverer.default when their decorated classes load.
// ChronicleOptions' discoveryPatterns can also import files that match glob patterns.
function createStructuralDependenciesDefaultArtifactsProvider(): DefaultClientArtifactsProvider {
    return new DefaultClientArtifactsProvider(TypeDiscoverer.default);
}
```

[View TypeScript snippet source on GitHub](https://github.com/Cratis/Chronicle.TypeScript/blob/main/Documentation/client-snippets/configuration/structural-dependencies/default-artifacts-provider.md)

</TabItem>
</Tabs>

The static `DefaultClientArtifactsProvider.Default` instance is used when no provider is supplied.

> **Note:** `DefaultClientArtifactsProvider` initializes lazily on first property access; no explicit initialization is required.
