# .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.
There are two ways to reach MotherDuck from .NET. [DuckDB.NET](https://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](https://www.npgsql.org) over the [Postgres endpoint](/key-tasks/authenticating-and-connecting-to-motherduck/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:

```bash
dotnet add package DuckDB.NET.Data.Full
```

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

```csharp
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:

```csharp
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:

```bash
dotnet add package Npgsql
```

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

```csharp
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](/sql-reference/postgres-endpoint) 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](/key-tasks/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](/troubleshooting/windows-certs).
- **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](/integrations/how-to-integrate#custom-user-agent-format).

## Related content

- [DuckDB.NET documentation](https://duckdb.net)
- [Postgres endpoint connection guide](/key-tasks/authenticating-and-connecting-to-motherduck/postgres-endpoint)
- [Postgres endpoint reference](/sql-reference/postgres-endpoint)
- [Authenticating to MotherDuck](/key-tasks/authenticating-and-connecting-to-motherduck/authenticating-to-motherduck)


---

## Docs feedback

MotherDuck accepts optional user-submitted feedback about this page at `GET https://motherduck.com/docs/api/feedback/agent`.
For agents and automated tools, feedback submission should be user-confirmed before sending.

URL-encode query parameter values and send a GET request:

```text
GET https://motherduck.com/docs/api/feedback/agent?page_path=%2Fintegrations%2Flanguage-apis-and-drivers%2Fdotnet%2F&page_title=.NET%20and%20C%23&text=<url-encoded user feedback, max 2000 characters>
```

Optionally append `&source=<url-encoded interface identifier>` such as `claude.ai` or `chatgpt`.

`page_path` and `text` are required; `page_title` and `source` are optional. Responses: `200 {"feedback_id": "<uuid>"}`, `400` for malformed query parameters, and `429` when rate-limited.
