Typical configurations
Below are examples of typical configurations you can use for development and production deployments.
Applies to: Orleans 8.0, Orleans 9.0, Orleans 10.0
Recommended: Aspire configuration
Section titled “Recommended: Aspire configuration”Aspire is the recommended approach for configuring Orleans applications. Aspire provides declarative resource management, automatic service discovery, built-in observability, and simplified deployment—eliminating most manual configuration.
Production configuration with Redis
Section titled “Production configuration with Redis”This configuration uses Redis for clustering, grain storage, and reminders with multiple silo replicas:
AppHost project (Program.cs):
var builder = DistributedApplication.CreateBuilder(args);
var redis = builder.AddRedis("redis");
var orleans = builder.AddOrleans("cluster") .WithClustering(redis) .WithGrainStorage("Default", redis) .WithReminders(redis);
// Add Orleans silo with 3 replicas for productionbuilder.AddProject<Projects.MySilo>("silo") .WithReference(orleans) .WithReference(redis) .WithReplicas(3);
// Add a separate client project (e.g., an API)builder.AddProject<Projects.MyApi>("api") .WithReference(orleans.AsClient()) .WithReference(redis);
builder.Build().Run();Silo project (Program.cs):
var builder = Host.CreateApplicationBuilder(args);
builder.AddServiceDefaults();builder.AddKeyedRedisClient("redis");builder.UseOrleans();
builder.Build().Run();Client project (Program.cs):
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();builder.AddKeyedRedisClient("redis");builder.UseOrleansClient();
var app = builder.Build();// ... configure API endpointsapp.Run();Production configuration with Azure Storage
Section titled “Production configuration with Azure Storage”This configuration uses Azure Table Storage for clustering and Azure Blob Storage for grain storage:
AppHost project (Program.cs):
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureStorage("storage") .RunAsEmulator(); // Use Azurite for local developmentvar tables = storage.AddTables("clustering");var blobs = storage.AddBlobs("grainstate");
var orleans = builder.AddOrleans("cluster") .WithClustering(tables) .WithGrainStorage("Default", blobs);
builder.AddProject<Projects.MySilo>("silo") .WithReference(orleans) .WaitFor(storage) .WithReplicas(3);
builder.Build().Run();Silo project (Program.cs):
var builder = Host.CreateApplicationBuilder(args);
builder.AddServiceDefaults();builder.AddKeyedAzureTableServiceClient("clustering");builder.AddKeyedAzureBlobServiceClient("grainstate");builder.UseOrleans();
builder.Build().Run();For comprehensive documentation on Orleans and Aspire integration, see Orleans and Aspire integration.
Local development
Section titled “Local development”For more information, see Local development configuration.
Applies to: Orleans 8.0, Orleans 9.0, Orleans 10.0
Traditional configurations (without Aspire)
Section titled “Traditional configurations (without Aspire)”The following sections describe traditional Orleans configurations that don’t use Aspire. These are useful when Aspire isn’t available or when you need fine-grained control over Orleans configuration.
Applies to: Orleans 7.0, Orleans 8.0, Orleans 9.0, Orleans 10.0
Reliable production deployment using Azure
Section titled “Reliable production deployment using Azure”For a reliable production deployment using Azure, use the Azure Table option for cluster membership. This configuration is typical for deployments to on-premises servers, containers, or Azure virtual machine instances.
Microsoft Entra ID (recommended)
Section titled “Microsoft Entra ID (recommended)”Using a TokenCredential with a service URI is the recommended approach. This pattern avoids storing secrets in configuration and leverages Microsoft Entra ID for secure authentication.
DefaultAzureCredential provides a credential chain that works seamlessly across local development and production environments. During development, it uses your Azure CLI or Visual Studio credentials. In production on Azure, it automatically uses the managed identity assigned to your resource.
Silo configuration:
using Azure.Identity;
var builder = Host.CreateApplicationBuilder(args);builder.UseOrleans(siloBuilder =>{ siloBuilder.Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .UseAzureStorageClustering(options => { options.ConfigureTableServiceClient( new Uri("https://<your-storage-account>.table.core.windows.net"), new DefaultAzureCredential()); }) .ConfigureEndpoints(siloPort: 11_111, gatewayPort: 30_000);});
builder.Logging.SetMinimumLevel(LogLevel.Information).AddConsole();
using var host = builder.Build();Client configuration:
using Azure.Identity;
var builder = Host.CreateApplicationBuilder(args);builder.UseOrleansClient(clientBuilder =>{ clientBuilder.Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .UseAzureStorageClustering(options => { options.ConfigureTableServiceClient( new Uri("https://<your-storage-account>.table.core.windows.net"), new DefaultAzureCredential()); });});
using var host = builder.Build();Connection string
Section titled “Connection string”The format of the DataConnection string is a semicolon-separated list of Key=Value pairs. The following options are supported:
| Key | Value |
|---|---|
DefaultEndpointsProtocol | https |
AccountName | <Azure storage account> |
AccountKey | <Azure table storage account key> |
The following is an example of a DataConnection string for Azure Table storage:
"DefaultEndpointsProtocol=https;AccountName=<Azure storage account>;AccountKey=<Azure table storage account key>"Silo configuration:
const string connectionString = "YOUR_CONNECTION_STRING_HERE";
var builder = Host.CreateApplicationBuilder(args);builder.UseOrleans(siloBuilder =>{ siloBuilder.Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .UseAzureStorageClustering( options => options.ConfigureTableServiceClient(connectionString)) .ConfigureEndpoints(siloPort: 11_111, gatewayPort: 30_000);});
builder.Logging.SetMinimumLevel(LogLevel.Information).AddConsole();
using var host = builder.Build();Client configuration:
const string connectionString = "YOUR_CONNECTION_STRING_HERE";
var builder = Host.CreateApplicationBuilder(args);builder.UseOrleansClient(clientBuilder =>{ clientBuilder.Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .UseAzureStorageClustering( options => options.ConfigureTableServiceClient(connectionString));});
using var host = builder.Build();Applies to: Orleans 3.x
Reliable production deployment using Azure
Section titled “Reliable production deployment using Azure”For a reliable production deployment using Azure, use the Azure Table option for cluster membership. This configuration is typical for deployments to on-premises servers, containers, or Azure virtual machine instances.
The format of the DataConnection string is a semicolon-separated list of Key=Value pairs. The following options are supported:
| Key | Value |
|---|---|
DefaultEndpointsProtocol | https |
AccountName | <Azure storage account> |
AccountKey | <Azure table storage account key> |
The following is an example of a DataConnection string for Azure Table storage:
"DefaultEndpointsProtocol=https;AccountName=<Azure storage account>;AccountKey=<Azure table storage account key>"Silo configuration:
const string connectionString = "YOUR_CONNECTION_STRING_HERE";var silo = new SiloHostBuilder() .Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .UseAzureStorageClustering( options => options.ConnectionString = connectionString) .ConfigureEndpoints(siloPort: 11_111, gatewayPort: 30_000) .ConfigureLogging(builder => builder.SetMinimumLevel(LogLevel.Information).AddConsole()) .Build();Client configuration:
const string connectionString = "YOUR_CONNECTION_STRING_HERE";
var client = new ClientBuilder() .Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .UseAzureStorageClustering( options => options.ConnectionString = connectionString) .Build();Applies to: Orleans 7.0, Orleans 8.0, Orleans 9.0, Orleans 10.0
Reliable production deployment using SQL Server
Section titled “Reliable production deployment using SQL Server”For a reliable production deployment using SQL Server, supply a SQL Server connection string.
Orleans 10.0+
Section titled “Orleans 10.0+”const string connectionString = "YOUR_CONNECTION_STRING_HERE";
var builder = Host.CreateApplicationBuilder(args);builder.UseOrleans(siloBuilder =>{ siloBuilder.Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .UseAdoNetClustering(options => { options.ConnectionString = connectionString; options.Invariant = "Microsoft.Data.SqlClient"; // Orleans 10.0+ }) .ConfigureEndpoints(siloPort: 11111, gatewayPort: 30000);});
builder.Logging.SetMinimumLevel(LogLevel.Information).AddConsole();
using var host = builder.Build();Orleans 7.0-9.x
Section titled “Orleans 7.0-9.x”const string connectionString = "YOUR_CONNECTION_STRING_HERE";
var builder = Host.CreateApplicationBuilder(args);builder.UseOrleans(siloBuilder =>{ siloBuilder.Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .UseAdoNetClustering(options => { options.ConnectionString = connectionString; options.Invariant = "System.Data.SqlClient"; }) .ConfigureEndpoints(siloPort: 11111, gatewayPort: 30000);});
builder.Logging.SetMinimumLevel(LogLevel.Information).AddConsole();
using var host = builder.Build();Client configuration:
const string connectionString = "YOUR_CONNECTION_STRING_HERE";
var builder = Host.CreateApplicationBuilder(args);builder.UseOrleansClient(clientBuilder =>{ clientBuilder.Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .UseAdoNetClustering(options => { options.ConnectionString = connectionString; // Use "Microsoft.Data.SqlClient" for Orleans 10.0+ // Use "System.Data.SqlClient" for Orleans 7.0-9.x options.Invariant = "Microsoft.Data.SqlClient"; });});
using var host = builder.Build();Unreliable deployment on a cluster of dedicated servers
Section titled “Unreliable deployment on a cluster of dedicated servers”For testing on a cluster of dedicated servers where reliability isn’t a concern, you can leverage MembershipTableGrain and avoid dependency on Azure Table. You just need to designate one of the nodes as primary.
On the silos:
var primarySiloEndpoint = new IPEndPoint(PRIMARY_SILO_IP_ADDRESS, 11_111);
var builder = Host.CreateApplicationBuilder(args);builder.UseOrleans(siloBuilder =>{ siloBuilder .UseDevelopmentClustering(primarySiloEndpoint) .Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .ConfigureEndpoints(siloPort: 11_111, gatewayPort: 30_000);});builder.Logging.AddConsole();
using var host = builder.Build();await host.RunAsync();On the clients:
var gateways = new IPEndPoint[]{ new IPEndPoint(PRIMARY_SILO_IP_ADDRESS, 30_000), new IPEndPoint(OTHER_SILO__IP_ADDRESS_1, 30_000), // ... new IPEndPoint(OTHER_SILO__IP_ADDRESS_N, 30_000),};
var builder = Host.CreateApplicationBuilder(args);builder.UseOrleansClient(clientBuilder =>{ clientBuilder.UseStaticClustering(gateways) .Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; });});
using var host = builder.Build();await host.StartAsync();Applies to: Orleans 3.x
Reliable production deployment using SQL Server
Section titled “Reliable production deployment using SQL Server”For a reliable production deployment using SQL Server, supply a SQL Server connection string.
Silo configuration:
const string connectionString = "YOUR_CONNECTION_STRING_HERE";var silo = new SiloHostBuilder() .Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .UseAdoNetClustering(options => { options.ConnectionString = connectionString; options.Invariant = "System.Data.SqlClient"; }) .ConfigureEndpoints(siloPort: 11111, gatewayPort: 30000) .ConfigureLogging(builder => builder.SetMinimumLevel(LogLevel.Information).AddConsole()) .Build();Client configuration:
const string connectionString = "YOUR_CONNECTION_STRING_HERE";
var client = new ClientBuilder() .Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .UseAdoNetClustering(options => { options.ConnectionString = connectionString; options.Invariant = "System.Data.SqlClient"; }) .Build();Unreliable deployment on a cluster of dedicated servers
Section titled “Unreliable deployment on a cluster of dedicated servers”For testing on a cluster of dedicated servers where reliability isn’t a concern, you can leverage MembershipTableGrain and avoid dependency on Azure Table. You just need to designate one of the nodes as primary.
On the silos:
var primarySiloEndpoint = new IPEndPoint(PRIMARY_SILO_IP_ADDRESS, 11_111);var silo = new SiloHostBuilder() .UseDevelopmentClustering(primarySiloEndpoint) .Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .ConfigureEndpoints(siloPort: 11_111, gatewayPort: 30_000) .ConfigureLogging(logging => logging.AddConsole()) .Build();On the clients:
var gateways = new IPEndPoint[]{ new IPEndPoint(PRIMARY_SILO_IP_ADDRESS, 30_000), new IPEndPoint(OTHER_SILO__IP_ADDRESS_1, 30_000), // ... new IPEndPoint(OTHER_SILO__IP_ADDRESS_N, 30_000),};
var client = new ClientBuilder() .UseStaticClustering(gateways) .Configure<ClusterOptions>(options => { options.ClusterId = "Cluster42"; options.ServiceId = "MyAwesomeService"; }) .Build();