Skip to main content

Amazon DynamoDB Provider

The DynamoDB provider implements ICloudNativePersistenceProvider for AWS serverless workloads with hash/sort key support, DynamoDB Streams integration, and transactional batch operations.

Before You Start

Installation

dotnet add package Excalibur.Data.DynamoDb

Dependencies: Excalibur.Data.Abstractions, AWSSDK.DynamoDBv2

Quick Start

using Microsoft.Extensions.DependencyInjection;

services.AddExcaliburDynamoDb(dynamo =>
{
dynamo.Region(RegionEndpoint.USEast1)
.TablePrefix("MyApp_");
});

Registration

The builder API (IDynamoDBDataBuilder) supports 4 canonical connection overloads plus configuration binding:

// AWS Region (uses default credentials / IAM role)
services.AddExcaliburDynamoDb(dynamo =>
dynamo.Region(RegionEndpoint.USEast1).TableName("MyTable"));

// Local DynamoDB / LocalStack
services.AddExcaliburDynamoDb(dynamo =>
dynamo.ServiceUrl("http://localhost:8000").TableName("MyTable"));

// Existing IAmazonDynamoDB client
services.AddExcaliburDynamoDb(dynamo =>
dynamo.Client(existingClient).TableName("MyTable"));

// Client factory (for custom configuration)
services.AddExcaliburDynamoDb(dynamo =>
dynamo.ClientFactory(sp => new AmazonDynamoDBClient(credentials, region))
.TableName("MyTable"));

// IConfiguration binding
services.AddExcaliburDynamoDb(dynamo =>
dynamo.BindConfiguration("DynamoDb"));

All registrations include ValidateOnStart for options validation.

Projection Store

Projections are stored flat at the document root. Framework metadata is isolated under a _projection nested object to avoid collisions with your projection properties. See Projections — Document Storage Format for details.

Subsystem Registration

Each Excalibur subsystem supports DynamoDB via its own builder:

services.AddExcalibur(excalibur =>
{
// Event Sourcing
excalibur.AddEventSourcing(es =>
es.UseDynamoDb(dynamo =>
dynamo.Region(RegionEndpoint.USEast1)
.TableName("Events")
.TablePrefix("MyApp_")));

// Saga
excalibur.AddSaga(saga =>
saga.UseDynamoDb(dynamo =>
dynamo.Region(RegionEndpoint.USEast1)
.TableName("Sagas")));

// Inbox (idempotency)
excalibur.AddInbox(inbox =>
inbox.UseDynamoDb(dynamo =>
dynamo.Region(RegionEndpoint.USEast1)
.TableName("Inbox")));

// Outbox (reliable messaging)
excalibur.AddOutbox(outbox =>
outbox.UseDynamoDb(dynamo =>
dynamo.Region(RegionEndpoint.USEast1)
.TableName("Outbox")));
});

Change Data Capture

services.AddCdcProcessor(cdc =>
{
cdc.UseDynamoDb(dynamo =>
{
dynamo.TableName("Orders")
.StreamArn("arn:aws:dynamodb:us-east-1:123456789:table/Orders/stream/2026-01-01T00:00:00.000")
.ProcessorName("order-processor")
.WithStateStore(
sp => new AmazonDynamoDBClient(),
state => state.TableName("CdcState"));
})
.TrackTable("Orders", t => t.MapAll<OrderChangedEvent>())
.EnableBackgroundProcessing();
});

Builder Methods

Connection Methods

All 5 non-CDC subsystem builders share the same connection methods:

MethodDescription
ServiceUrl(string)Local DynamoDB or LocalStack endpoint URL
Region(RegionEndpoint)AWS region (uses default credential chain)
Client(IAmazonDynamoDB)Pre-configured client instance
ClientFactory(Func<IServiceProvider, IAmazonDynamoDB>)Factory for custom client creation
BindConfiguration(string)Bind from IConfiguration section

Connection methods follow last-wins semantics — calling Client() after Region() replaces the region-based connection.

Domain Methods

MethodDescriptionAvailable On
TableName(string)DynamoDB table nameAll 6 builders
TablePrefix(string)Prefix for table names5 builders (not CDC)
StreamArn(string)DynamoDB Streams ARNCDC only
ProcessorName(string)CDC processor nameCDC only
WithStateStore(...)CDC state store configurationCDC only

Partition and Sort Keys

DynamoDB uses hash keys and optional sort keys:

var key = new PartitionKey("USER#user-123", "/pk");
var result = await provider.GetByIdAsync<UserProfile>(
"PROFILE#main", key,
consistencyOptions: null,
cancellationToken: ct);

Batch Operations

Execute multiple operations atomically:

var batchResult = await provider.ExecuteBatchAsync(
partitionKey,
operations,
cancellationToken: ct);

Configuration Binding

Bind DynamoDB options from appsettings.json:

{
"DynamoDb": {
"Connection": {
"Region": "us-east-1",
"ServiceUrl": null
},
"DefaultTableName": "MyTable",
"DefaultPartitionKeyAttribute": "pk",
"DefaultSortKeyAttribute": "sk",
"UseConsistentReads": false
}
}
services.AddExcaliburDynamoDb(dynamo =>
dynamo.BindConfiguration("DynamoDb"));

See Also