Getting started with Aspire

This page starts a local FoundationDB cluster with .NET Aspire and connects one service to it. When you are done, the service reads a live value from the cluster on startup, and the first run configures the database for you. Ten minutes, one path. For the design behind the two packages and the connection flow, read the explanation; for single tasks like connecting to an existing cluster or pinning a version, see the how-to guides; for the full parameter tables, see the reference.

This page assumes you already have an Aspire solution with an AppHost project (Acme.AppHost) and one service project (Acme.Backend). If you do not, create one first with the Aspire templates, then come back. You also need Docker running, because the AppHost starts the cluster in a container.

1. Install the SDK packages

The host package goes in the AppHost, the client package in the service. Both carry the library version:

# in Acme.AppHost
dotnet add package FoundationDB.Aspire.Hosting

# in Acme.Backend
dotnet add package FoundationDB.Aspire

Or add the references to your project files directly:

<!-- Acme.AppHost.csproj -->
<ItemGroup>
  <!-- other packages -->
  <PackageReference Include="FoundationDB.Aspire.Hosting" Version="7.4.6" />
</ItemGroup>

<!-- Acme.Backend.csproj -->
<ItemGroup>
  <!-- other packages -->
  <PackageReference Include="FoundationDB.Aspire" Version="7.4.6" />
</ItemGroup>

The native client (FoundationDB.Client.Native) comes in step 3, after you choose the cluster version, because its version tracks the cluster and not these packages.

2. Declare the cluster in the AppHost

In Acme.AppHost/Program.cs, add the cluster and give the backend a reference to it:

var builder = DistributedApplication.CreateBuilder(args);

// Start a local single-node FoundationDB cluster in Docker.
// apiVersion is the API level the services request; clusterVersion is the Docker image tag;
// root is the directory-layer path the services resolve keys under.
var fdb = builder.AddFoundationDb("fdb",
    apiVersion: 740,
    root: "/Sandbox/Acme",
    clusterVersion: "7.4.6",
    rollForward: FdbVersionPolicy.Exact);

// Give the backend a reference to the cluster, and start it only once the cluster is healthy.
builder.AddProject<Projects.Acme_Backend>("backend")
    .WithReference(fdb)
    .WaitFor(fdb);

builder.Build().Run();

AddFoundationDb runs the cluster as a Docker container. WithReference(fdb) passes the connection string to the backend under the resource name ("fdb"), and WaitFor(fdb) holds the backend until the cluster reports healthy.

3. Install the native client to match the cluster

The cluster you declared is 7.4 (clusterVersion: "7.4.6", apiVersion: 740). Install the native client at that same major.minor in the service:

# in Acme.Backend
dotnet add package FoundationDB.Client.Native --version "7.4.*"

Or add the reference to the service project file:

<!-- Acme.Backend.csproj -->
<ItemGroup>
  <!-- other packages -->
  <PackageReference Include="FoundationDB.Client.Native" Version="7.4.*" />
</ItemGroup>

The native client sets the output format, so its version tracks the cluster, not the SDK packages. FoundationDB.Aspire stays at the library version (7.4.6), and FoundationDB.Client.Native follows clusterVersion. If you later target a 7.3 cluster, set apiVersion to 730 and clusterVersion to a 7.3.x in step 2, and change this pin to 7.3.*: the two always move together. A mismatch is the usual reason a service connects and then times out on every operation; see How it connects.

4. Read the connection in the service

In Acme.Backend/Program.cs, register FoundationDB from the injected connection, then add an endpoint that reads from it:

using FoundationDB.Client;
using FoundationDB.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);

// standard Aspire wiring (telemetry, health checks)
builder.AddServiceDefaults();

// "fdb" matches the name used in AddFoundationDb(...) in the AppHost.
// This registers the IFdbDatabaseProvider singleton.
builder.AddFoundationDb("fdb");

var app = builder.Build();

// Prove the connection: GetReadVersionAsync is a cheap round-trip, so a value here means it works.
app.MapGet("/readversion", async (IFdbDatabaseProvider db, CancellationToken ct) =>
{
    long readVersion = await db.ReadAsync(tr => tr.GetReadVersionAsync(), ct);
    return Results.Ok(new { readVersion });
});

app.Run();

AddFoundationDb("fdb") reads the injected connection string and registers the IFdbDatabaseProvider singleton, already pointed at the cluster the AppHost started. From here the read and write API is the same as Getting Started; the endpoint above only reads the cluster's current read version to prove the connection.

5. Run it

Start the AppHost with the aspire CLI, which provisions the dashboard and ports for you:

dotnet tool install --global aspire.cli    # one time
aspire run --apphost Acme.AppHost/Acme.AppHost.csproj

The dashboard opens in your browser. On this first run the fdb resource starts on a fresh volume, so the AppHost configures the database once and logs that it created it; the resource then turns healthy, and the backend starts (it waited for the cluster). The whole first start is unattended: no manual fdbcli step.

Open the backend's /readversion endpoint from the dashboard. You get a live number:

{ "readVersion": 143602331405 }

That is the success: the read version is a value from the cluster, so a real connection happened.

Stop the AppHost and run it again. The second run reuses nothing by default (a fresh container and a fresh volume), so it provisions again. To keep the container and its data across runs, add .WithLifetime(ContainerLifetime.Persistent) to the cluster; then a later run finds the database already configured and skips the step. The how-to guides cover that and the other common tasks.

Where to go next

You have a cluster Aspire starts for you and a service that connects to it through IFdbDatabaseProvider.

  • How-to guides: connect to an existing cluster, reuse the container across runs, pin or roll the cluster version, turn off autoprovisioning.
  • Getting Started: the read and write API you use once the provider is registered.
  • What it is and why: the host and client split, the connection flow, and how a fresh cluster provisions itself.