The Aspire integration: what it is and why
.NET Aspire starts a local FoundationDB cluster for you and hands its connection to every service that needs it. This page explains what the integration is and why it is shaped this way; for the step-by-step first run see Getting started, for the task recipes see How-to guides, and for the parameter and modifier tables see the reference.
Without Aspire you start a container, wait for it, configure the database, and copy a cluster file into each service by hand (the Cluster setup page walks that path). The Aspire integration does all of it: the AppHost describes the cluster once, and each service reads its connection from configuration.
The host and client split
The integration ships as two packages, and each goes in a different kind of project:
FoundationDB.Aspire.Hostinggoes in the AppHost. It defines the cluster resource withAddFoundationDb(a container Aspire runs for you) orAddFoundationDbCluster(an existing cluster you connect to).FoundationDB.Aspiregoes in each service that talks to the cluster. It reads the injected connection and registers theIFdbDatabaseProvidersingleton the rest of your code resolves.
The split follows Aspire's own model: the AppHost is the orchestrator that knows every resource and
how they connect, and a service knows only its own configuration. A service never names a host, a
port, or a cluster file; it names the resource ("fdb"), and the AppHost supplies the rest.
How the connection flows
One name ties the two sides together. AddFoundationDb("fdb", ...) in the AppHost declares a
resource called "fdb". WithReference(fdb) on a project injects that resource's connection string
into the project under the same name. AddFoundationDb("fdb") in the service reads the connection
string back by that name and registers the provider:
AppHost: AddFoundationDb("fdb", ...) defines the cluster
project.WithReference(fdb) injects the "fdb" connection string
Service: AddFoundationDb("fdb") reads "fdb", registers IFdbDatabaseProvider
The connection string is the only thing that crosses the boundary, so the same service code connects
to a local container in development and to a production cluster in staging. Only the AppHost changes.
WaitFor(fdb) holds a dependent project until the cluster reports healthy, so a service does not
start against a database that cannot yet answer.
A fresh cluster provisions itself
A FoundationDB database on a brand-new storage volume is not usable until it is configured once. Run
status against it and it reports "The database is unavailable"; a client that opens it waits, with
no error, for a configuration step that never comes. On a first run this reads as a hang: the AppHost
sits at near-zero CPU and nothing starts.
The integration removes that first-run trap. When the cluster container starts on a fresh volume, the
AppHost runs configure new single ssd inside it, then holds every resource that waits on the cluster
until the database answers. An already-configured database is left untouched, so a restart with a
persistent volume skips the step and logs that the database is already configured. The work is
idempotent and safe when two starters race; two AppHosts against one fresh volume converge on one
configured database, not two conflicting ones.
Two properties make this safe to leave on by default. The wait is bounded, not infinite: if the
database does not become available in time, the AppHost fails and names the manual
fdbcli --exec "configure new single ssd" recipe, rather than hanging in silence. And the happy path
logs that it configured the database, so a first run is never quiet. Turn the behavior off with
WithAutoProvisioning(false) on the cluster resource when you want to manage configuration yourself.
The same provisioning primitive backs the test harness. A freshly created FoundationDB test container
self-provisions its database on first start, so a test suite needs no manual fdbcli step.
Local or external
Two AppHost methods cover the two cases, and a service cannot tell them apart:
AddFoundationDb(...)runs a FoundationDB container from thefoundationdb/foundationdbDocker image. Use it for local development. It needs Docker on the development machine.AddFoundationDbCluster(...)starts no container. It passes a cluster file you supply to the referencing projects. Use it for staging, production, or any cluster Aspire did not start.
Both inject a connection string under the resource name, so a service written against one works against the other with no code change.
Version compatibility
FoundationDB couples the native client to the cluster, and that version is separate from the SDK
packages. The native fdb_c client a service loads (FoundationDB.Client.Native) must match the
running cluster within a major.minor version, and the API version a service selects must be at or
below the cluster version. The AppHost picks the cluster version (clusterVersion) and the API
version (apiVersion) in one call, so those two agree; the service's native package is a separate pin
the developer keeps matching to that cluster version. The FoundationDB.Aspire and
FoundationDB.Aspire.Hosting packages carry the SDK's own version, unrelated to the cluster. The
How it connects page covers the client and cluster versioning in full.
Where it sits
The integration's job ends where the other guides begin: it registers the IFdbDatabaseProvider that
Getting Started and the Guide assume you already have.
From the provider you open the database and read and write exactly as those pages describe.
One detail leaks through in local development: Aspire maps the cluster to its own host port, not the
4500 the plain-Docker walkthroughs use, so connect with the address Aspire prints in its dashboard
rather than a hard-coded one.