---
title: "Setup - Lattice Public API Reference"
url: "https://nsta1.github.io/Orleans.Lattice/docs/lattice/api/setup.html"
source: "https://github.com/NSTA1/Orleans.Lattice/blob/release/9.9/docs/lattice/api.md?plain=1#L17-L163"
package: "Orleans.Lattice"
version: "9.9.0"
documents: "Orleans.Lattice 9.9.0 (release line 9.9)"
built: "2026-10-04"
all-pages: "https://nsta1.github.io/Orleans.Lattice/llms.txt"
bundle: "https://nsta1.github.io/Orleans.Lattice/docs/lattice/llms-full.txt"
---
# Setup

Part of [Lattice Public API Reference](../api.md).

Install the NuGet package:

```shell
dotnet add package Orleans.Lattice
```

Import the namespace:

```csharp verify
using Orleans.Lattice;
```

Register Lattice on the silo, providing a grain-storage provider. The
callback receives the silo builder and the provider name that Lattice
grains will resolve against; register any Orleans grain-storage
provider under that name.

In-memory (development / tests):

```csharp verify
siloBuilder.AddLattice((silo, storageName) =>
    silo.AddMemoryGrainStorage(storageName));
```

Azure Table Storage (production). Requires the
`Microsoft.Orleans.Persistence.AzureStorage` and
`Orleans.Lattice.Storage.AzureTable` NuGet packages. The first
configures the grain-storage provider for tree state; the second
replaces the default in-memory WAL with a durable Azure Table-backed
provider:

```csharp verify
using Azure.Data.Tables;
using Microsoft.Extensions.DependencyInjection;
using Orleans.Lattice.Storage.AzureTable;

var connectionString = "UseDevelopmentStorage=true";

siloBuilder.AddLattice((services, storageName) =>
{
    services.AddAzureTableGrainStorage(storageName, options =>
    {
        options.TableServiceClient = new TableServiceClient(connectionString);
    });
});

siloBuilder.AddAzureTableWalStorage(o =>
{
    o.ConnectionString = connectionString;
});
```

Managed-identity deployments can either configure each extension
independently against the same storage account, or - for the canonical
"one credential, one client" shape - share a single pre-built
`TableServiceClient` between them: `AddAzureTableGrainStorage` accepts
a pre-built `TableServiceClient(serviceUri, credential)` via its
`options.TableServiceClient` slot, and `AddAzureTableWalStorage`
accepts the same instance via `options.ServiceClient`. Hosts that prefer
per-extension wiring can instead configure `AddAzureTableWalStorage`
with `ServiceUri` + `TokenCredential` (e.g.
`new DefaultAzureCredential()`) directly on its options object. See
[WAL Storage Providers](../wal-storage-providers.md) for the full set of
WAL authentication modes.

> The `AddLattice` callback configures the **grain-storage** provider
> Lattice uses for its tree state. The silo also requires an
> `IWalStorageProvider` for the write-ahead log; `AddLattice`
> registers the in-memory provider by default (suitable for
> development and single-process tests), and hosts that need
> durability across silo restarts must replace it with a persistent
> provider before going to production. See
> [WAL Storage Providers](../wal-storage-providers.md) for the
> `AddAzureTableWalStorage` extension shipped by the
> `Orleans.Lattice.Storage.AzureTable` package and the
> `AddWalStorage` seam for hosting custom providers.

Per-tree options are configured via `ConfigureLattice` (see
[Configuration](../configuration.md) for the full options reference and
per-tree override semantics):

```csharp verify
siloBuilder.ConfigureLattice("my-tree", o =>
{
    o.CacheTtl = TimeSpan.FromMilliseconds(100);
    o.HotShardOpsPerSecondThreshold = 500;
});
```

> **Cross-cluster replication** is layered on top of the core library
> by the `Orleans.Lattice.Replication` package via
> `AddLatticeReplication`. Peer membership (who this silo ships its
> WAL to) is configured through `LatticeReplicationOptions.ReplicationPeers`
> or a custom `IReplicationTopology` registration - both are documented
> in [Replication drivers: Peer configuration](../../lattice.replication/replication-drivers.md#peer-configuration-topology-vs-replicationpeers).
> The core `LatticeOptions` surface does not carry peer state.

> Structural sizing (`MaxLeafKeys`, `MaxInternalChildren`,
> `ShardCount`) is **not** configured here. Those values are pinned
> per-tree in the registry. See [Tree Sizing](../tree-sizing.md) for how
> to set them on a new or existing tree.

> For a runnable end-to-end example, see [Samples](../samples.md).

## Basic usage

Once Lattice is registered on the silo, resolve an `ILattice` grain
from `IGrainFactory` using the tree's logical name as the string key:

```csharp verify
// Resolve the tree (idempotent - the same name always routes to the same tree).
var tree = grainFactory.GetGrain<ILattice>("my-tree");

// Write a value.
await tree.SetAsync("user:1", "Alice"u8.ToArray());

// Read it back (returns null when absent or tombstoned).
byte[]? value = await tree.GetAsync("user:1");

// Conditional write - insert only if the key is not already present.
byte[]? existing = await tree.GetOrSetAsync("user:1", "Bob"u8.ToArray());

// Delete (tombstones the key; returns true if it was live).
bool deleted = await tree.DeleteAsync("user:1");

// Stream a key range in strict lexicographic order.
await foreach (var key in tree.ScanKeysAsync(startInclusive: "user:", endExclusive: "user;"))
{
    Console.WriteLine(key);
}
```

Keys are `string`; values are `byte[]`. For typed payloads (POCOs,
records, DTOs) use the serializer-aware overloads in
[`TypedLatticeExtensions`](../api.md#typedlatticeextensions); they accept any
`T` and default to `JsonLatticeSerializer<T>`:

```csharp verify
await tree.SetAsync("user:1", new User("Alice", 30));
var user = await tree.GetAsync<User>("user:1");
```

For the full set of runtime and maintenance operations, see
[`ILattice`](ilattice.md) below.

Next: [ILattice](ilattice.md). Contents: [Lattice Public API Reference](../api.md).
