Skip to main content

.NET and C#

Connect to MotherDuck from .NET and C# with DuckDB.NET for a full DuckDB client, or with Npgsql over the MotherDuck Postgres endpoint for a pure managed dependency.

There are two ways to reach MotherDuck from .NET. DuckDB.NET is an ADO.NET provider over the native DuckDB library, which gives you the full DuckDB client including local files and extensions. Npgsql over the Postgres endpoint needs no native dependency at all, which suits serverless and container deployments.

Use DuckDB.NET when you want DuckDB locally as well as in the cloud. Use Npgsql when you only need to query MotherDuck and want a pure managed dependency.

DuckDB.NET

Add the package. The .Full variant bundles the native libraries for the common platforms:

dotnet add package DuckDB.NET.Data.Full

Connect with md: as the data source and your token as a connection-string parameter:

using DuckDB.NET.Data;

var token = Environment.GetEnvironmentVariable("MOTHERDUCK_TOKEN");

using var connection = new DuckDBConnection($"DataSource=md:my_db?motherduck_token={token}");
connection.Open();

using var command = connection.CreateCommand();
command.CommandText =
"SELECT title FROM sample_data.hn.hacker_news WHERE title IS NOT NULL LIMIT 5";

using var reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(reader.GetString(0));
}

The motherduck extension is autoinstalled and autoloaded the first time you connect to md:. Use DataSource=md: without a database name to attach all of your databases.

Parameterize queries rather than building SQL by hand:

using var command = connection.CreateCommand();
command.CommandText = "SELECT COUNT(*) FROM orders WHERE order_date >= $since";
command.Parameters.Add(new DuckDBParameter("since", new DateTime(2026, 1, 1)));

var count = command.ExecuteScalar();

Npgsql over the Postgres endpoint

Add the package:

dotnet add package Npgsql

Connect to the MotherDuck Postgres endpoint with postgres as the user and your token as the password:

using Npgsql;

var token = Environment.GetEnvironmentVariable("MOTHERDUCK_TOKEN");

var connectionString =
"Host=pg.us-east-1-aws.motherduck.com;" +
"Port=5432;" +
"Username=postgres;" +
$"Password={token};" +
"Database=md:;" +
"SslMode=VerifyFull";

await using var connection = new NpgsqlConnection(connectionString);
await connection.OpenAsync();

await using var command = new NpgsqlCommand(
"SELECT title FROM sample_data.hn.hacker_news WHERE title IS NOT NULL LIMIT 5",
connection);
await using var reader = await command.ExecuteReaderAsync();

while (await reader.ReadAsync())
{
Console.WriteLine(reader.GetString(0));
}

SslMode=VerifyFull validates the server certificate against your operating system's trust store, which is the recommended setting. Set Database to md: or to a specific database name.

You're writing DuckDB SQL over this connection, not PostgreSQL SQL, and the endpoint doesn't support local files, extension management, or Dual Execution. See the Postgres endpoint reference for the full list of limitations, and prefer long-lived pooled connections over one connection per query.

info

Store your MotherDuck token in an environment variable or a secret store rather than hardcoding it. Never put it in a connection string that gets logged.

Things to know

  • Entity Framework and ORMs. Npgsql is the practical route for ORM-backed code, since the Postgres provider ecosystem already exists. Expect to hand-write analytical queries: MotherDuck is analytical, so per-row SELECT and UPDATE patterns generated by an ORM perform poorly. See Query performance.
  • Windows certificate trust. On Windows, connections can fail with HTTP 400 or 500 errors when the Let's Encrypt root isn't trusted. See Install Let's Encrypt certificates on Windows.
  • Identify your integration. If you're shipping a tool other people will use, pass custom_user_agent in the DuckDB.NET connection string so your traffic is identifiable in query history. See Creating a new integration.