Skip to main content

Google Firestore Provider

The Firestore provider implements ICloudNativePersistenceProvider for Google Cloud workloads with real-time document listeners, hierarchical collection paths, and batch write support.

Before You Start

Installation

dotnet add package Excalibur.Data.Firestore

Dependencies: Excalibur.Data.Abstractions, Google.Cloud.Firestore

Quick Start

using Microsoft.Extensions.DependencyInjection;

services.AddExcaliburFirestore(firestore =>
{
firestore.ProjectId("my-gcp-project");
});

Registration

The builder API (IFirestoreDataBuilder) supports multiple connection approaches matching GCP SDK patterns:

// Project ID with Application Default Credentials (ADC)
services.AddExcaliburFirestore(firestore =>
firestore.ProjectId("my-gcp-project"));

// Project ID with explicit credentials
services.AddExcaliburFirestore(firestore =>
firestore.ProjectId("my-gcp-project")
.CredentialsPath("/path/to/service-account.json"));

// Project ID with inline JSON credentials
services.AddExcaliburFirestore(firestore =>
firestore.ProjectId("my-gcp-project")
.CredentialsJson(jsonString));

// Emulator (local development)
services.AddExcaliburFirestore(firestore =>
firestore.ProjectId("test-project")
.EmulatorHost("localhost:8080"));

// Existing FirestoreDb instance
services.AddExcaliburFirestore(firestore =>
firestore.Client(existingFirestoreDb));

// Client factory (for custom configuration)
services.AddExcaliburFirestore(firestore =>
firestore.ClientFactory(sp => CreateFirestoreDb(sp)));

// IConfiguration binding
services.AddExcaliburFirestore(firestore =>
firestore.BindConfiguration("Firestore"));

All registrations include ValidateOnStart for options validation.

Additive Credentials

Unlike other providers where connection methods are strictly last-wins, Firestore credential methods are additiveProjectId() and CredentialsPath()/CredentialsJson() can coexist. Only Client() and ClientFactory() clear all other connection state (last-wins).

Subsystem Registration

Each Excalibur subsystem supports Firestore via its own builder:

services.AddExcalibur(excalibur =>
{
// Event Sourcing
excalibur.AddEventSourcing(es =>
es.UseFirestore(firestore =>
firestore.ProjectId("my-project")
.CollectionName("events")));

// Saga
excalibur.AddSaga(saga =>
saga.UseFirestore(firestore =>
firestore.ProjectId("my-project")
.CollectionName("sagas")));

// Inbox (idempotency)
excalibur.AddInbox(inbox =>
inbox.UseFirestore(firestore =>
firestore.ProjectId("my-project")
.CollectionName("inbox")));

// Outbox (reliable messaging)
excalibur.AddOutbox(outbox =>
outbox.UseFirestore(firestore =>
firestore.ProjectId("my-project")
.CollectionName("outbox")));
});

Change Data Capture

services.AddCdcProcessor(cdc =>
{
cdc.UseFirestore(firestore =>
{
firestore.ProjectId("my-project")
.CollectionPath("orders")
.ProcessorName("order-processor")
.MaxBatchSize(100)
.PollInterval(TimeSpan.FromSeconds(5))
.WithStateStore(state =>
state.TableName("cdc-checkpoints"));
})
.TrackTable("orders", t => t.MapAll<OrderChangedEvent>())
.EnableBackgroundProcessing();
});

Builder Methods

Connection Methods

All 6 subsystem builders share GCP-specific connection methods:

MethodDescriptionBehavior
ProjectId(string)GCP project IDAdditive with credentials
CredentialsPath(string)Path to service account JSONAdditive with ProjectId
CredentialsJson(string)Inline service account JSONAdditive with ProjectId
EmulatorHost(string)Firestore emulator endpointAdditive with ProjectId
Client(FirestoreDb)Pre-configured instanceLast-wins (clears all)
ClientFactory(Func<IServiceProvider, FirestoreDb>)Factory for custom creationLast-wins (clears all)
BindConfiguration(string)Bind from IConfiguration sectionLast-wins (clears all)

Domain Methods

MethodDescriptionAvailable On
CollectionName(string)Firestore collection name5 builders (not CDC)
CollectionPath(string)Hierarchical collection pathCDC only
ProcessorName(string)CDC processor nameCDC only
MaxBatchSize(int)CDC batch sizeCDC only
PollInterval(TimeSpan)CDC polling intervalCDC only
WithStateStore(Action<ICdcStateStoreBuilder>)CDC state store configCDC only

Collection Hierarchies

Firestore supports hierarchical document/collection paths:

var key = new PartitionKey("users/user-123/orders", "/collection");
var orders = await provider.QueryAsync<Order>(
queryText: "",
key,
parameters: null,
consistencyOptions: null,
cancellationToken: ct);

Configuration Binding

Bind Firestore options from appsettings.json:

{
"Firestore": {
"ProjectId": "my-gcp-project",
"CredentialsPath": "/path/to/service-account.json",
"EmulatorHost": null,
"DefaultCollection": "default",
"TimeoutInSeconds": 30,
"MaxRetryAttempts": 3
}
}
services.AddExcaliburFirestore(firestore =>
firestore.BindConfiguration("Firestore"));

See Also