Watch Aspire live streamsDocumentazioneProva Aspire

Connect with the DuckDB integration

Questi contenuti non sono ancora disponibili nella tua lingua.

⭐ Community Toolkit

The DuckDB client integration registers an ADO.NET connection to an embedded database. Model and reference the file as shown in DuckDB hosting integration. The examples use a resource named analytics.

The resource produces one of these exact connection-string formats:

Writable connection
DataSource={databaseFilePath}
Read-only connection
DataSource={databaseFilePath};Access Mode=ReadOnly

Aspire injects the string as ConnectionStrings__analytics. .NET configuration reads ConnectionStrings:analytics.

PropertyEnvironment variableValue
DataSourceANALYTICS_DATASOURCEDatabase file path formed from the resource directory and filename.

The resource exposes no server host, port, or URI. DataSource contains only the path, not the access mode.

Install 📦 CommunityToolkit.Aspire.DuckDB.NET.Data in the consuming .NET project:

.NET CLI — Add CommunityToolkit.Aspire.DuckDB.NET.Data package
dotnet add package CommunityToolkit.Aspire.DuckDB.NET.Data

The package uses DuckDB.NET.Data.DuckDBConnection.

Register a scoped connection, then open it before executing SQL:

Program.cs
using DuckDB.NET.Data;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
builder.AddDuckDBConnection("analytics");
var app = builder.Build();
app.MapGet("/analytics", async (DuckDBConnection connection) =>
{
await connection.OpenAsync();
using var command = connection.CreateCommand();
command.CommandText = "SELECT CAST(SUM(i) AS BIGINT) FROM range(10) AS values_table(i)";
var total = await command.ExecuteScalarAsync();
return Results.Ok(Convert.ToInt64(total));
});
app.Run();

The query calculates a sum without requiring a table or seed data. Dependency injection disposes the scoped connection at the end of the request.

The connection name must match the referenced resource name. Registration creates a closed connection; it does not run migrations or initialize application tables.

Use a keyed scoped connection to select a database by name:

Program.cs
using DuckDB.NET.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
builder.AddKeyedDuckDBConnection("analytics");
var app = builder.Build();
app.MapGet("/analytics", async (
[FromKeyedServices("analytics")] DuckDBConnection connection) =>
{
await connection.OpenAsync();
using var command = connection.CreateCommand();
command.CommandText = "SELECT 1";
return Results.Ok(await command.ExecuteScalarAsync());
});
app.Run();

For multiple databases, add a keyed registration for each name and reference the corresponding resources from the AppHost. See .NET dependency injection: Keyed services.

DuckDBConnectionSettings exposes ConnectionString and DisableHealthChecks. The disable flag defaults to false. There are no integration settings for retries, tracing, metrics, or command timeouts.

For a standalone app, provide the same connection name in configuration:

appsettings.json
{
"ConnectionStrings": {
"analytics": "DataSource=C:\\Data\\analytics.duckdb"
}
}

Use DataSource=:memory: for an in-memory database. It is not the AppHost file resource and does not persist data to disk.

The non-keyed client binds Aspire:DuckDB:Client. A keyed client binds Aspire:DuckDB:Client:{name}:

appsettings.json
{
"Aspire": {
"DuckDB": {
"Client": {
"ConnectionString": "DataSource=C:\\Data\\analytics.duckdb",
"DisableHealthChecks": false,
"analytics": {
"ConnectionString": "DataSource=C:\\Data\\analytics.duckdb",
"DisableHealthChecks": false
}
}
}
}
}

The root Client settings apply to AddDuckDBConnection. The nested analytics settings apply to AddKeyedDuckDBConnection("analytics"); keyed registration binds that subsection rather than merging it with the root.

The named ConnectionStrings value overrides the settings section’s ConnectionString. An inline delegate runs last. Validation is delayed until a connection is resolved.

Configure settings after connection-string binding:

Program.cs
using DuckDB.NET.Data;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
builder.AddDuckDBConnection("analytics", settings =>
{
settings.DisableHealthChecks = true;
});
var app = builder.Build();
app.MapGet("/analytics", async (DuckDBConnection connection) =>
{
await connection.OpenAsync();
using var command = connection.CreateCommand();
command.CommandText = "SELECT 1";
return Results.Ok(await command.ExecuteScalarAsync());
});
app.Run();

The integration creates a separate connection, opens it, and executes SELECT 1. The check is named DuckDB for a non-keyed registration or DuckDB_{name} for a keyed registration. Set DisableHealthChecks=true to omit it.

A writable health-check connection can create a missing database file. A read-only check requires an existing file. For :memory:, the check opens a separate in-memory database and does not verify the application’s tables.

Use service defaults to expose the registered health checks. The package does not map HTTP health endpoints itself.

This client integration does not register OpenTelemetry tracing, metrics, or a logging provider. Configure application instrumentation and exporters separately. The AppHost’s Running file-resource state is not proof of successful SQL execution.

Use the injected ANALYTICS_DATASOURCE path with each language’s DuckDB client. The following examples require an existing database file and explicitly open it read-only. They do not infer the access mode from the DataSource property.

Choose compatible DuckDB engine versions when several language clients open the same file.

Install the DuckDB Node.js Neo client:

Terminal
npm install @duckdb/node-api

Run this file with a TypeScript runner, or compile it for Node.js:

index.ts
import { DuckDBInstance } from '@duckdb/node-api';
const dataSource = process.env.ANALYTICS_DATASOURCE;
if (!dataSource) {
throw new Error('ANALYTICS_DATASOURCE is required');
}
const instance = await DuckDBInstance.create(dataSource, {
access_mode: 'READ_ONLY',
});
const connection = await instance.connect();
try {
const result = await connection.runAndReadAll('SELECT 1 AS value');
console.log(result.getRows());
} finally {
connection.closeSync();
}