# Npgsql 10.0 Release Notes

Npgsql version 10.0 is out and available on nuget.org.

##### Note

We're considering to start dropping support for synchronous APIs (`NpgsqlConnection.Open`, `NpgsqlCommand.ExecuteNonQuery`, etc.) starting with Npgsql 11.0. The current plan is to deprecate the API by throwing a runtime exception by default (with a switch to re-enable synchronous I/O) for Npgsql 11.0, while possibly completely removing it for Npgsql 12.0. This is in line with ASP.NET Core and .NET APIs in general, which are moving in the direction of async I/O only (for example, `System.IO.Pipelines` doesn't have synchronous I/O). If you have any questions or want to share you experience/issues with async I/O, please feel free to post in the issue.

While this is a relatively minor release in terms of changes, it does contain new features and improvements. Notable changes:

## Tracing and metrics improvements

Npgsql 10.0 brings multiple observability improvements:

- Command tracing has been changed to align with the stable OpenTelemetry tracing semantic conventions. This allows tracing any database driver using the same span and tags.
- Metrics support has also been changed to conform to the OpenTelemetry metrics semantic conventions. The stable `db.client.operation.duration` metric is now emitted, as well as the non-stable `db.client.connection.count`, `db.client.connection.max`. The remaining Npgsql-specific metrics have been renamed for consistency.
- COPY operations (binary, text and raw import/export) are now fully traced. Thanks to @manandre for contributing this feature!
- The opening of physical connections is now also traced, allowing you to observe and identify performance issues.

Note that these changes modify the metric names and tracing span tags, and so are breaking to anyone currently consuming Npgsql tracing/metrics.

## GSSAPI session encryption

GSSAPI session encryption is an alternative to SSL/TLS session encryption, where special temporary tokens are used to encrypt traffic between the client and the server (MIT Kerberos is one of the GSSAPI providers that can be used for that), unlike SSL/TLS, where the SSL certificate is used for the same purpose. You can use the `GssEncryptionMode` connection string parameter to control whether GSS session encryption is used; the default is `Prefer`, which will enable the feature if possible but proceed if it's not available.

To learn more, see the security and encryption docs.

## Support for RequireAuth in connection string

`RequireAuth` is used to determine which authentication methods are allowed/required. For example, if you want to make sure that passwords aren't sent as cleartext or MD5, you can specify `RequireAuth=!Password,!MD5`. Or, if you want to make sure to always authenticate either via ScramSHA256 or GSS, then you can specify it as `RequireAuth=ScramSHA256,GSS`. To learn more, see PostgreSQL docs.

## Support for the cube extension

PostgreSQL bundles the `cube` extension, which provides a multi-dimensional cube data type and associated operations. Npgsql 10 now fully supports the `cube` type out-of-the-box:

    command.CommandText = """
        CREATE EXTENSION IF NOT EXISTS cube;
        CREATE TABLE data (my_cude CUBE);
    """;
    await command.ExecuteNonQueryAsync();

    var cube = new NpgsqlCube([1.0, 2.0, 3.0], [4.0, 5.0, 6.0]);
    command.CommandText = "INSERT INTO data (my_cude) VALUES ($1)";
    command.Parameters.Add(new() { Value = cube });
    await command.ExecuteNonQueryAsync();

    command.CommandText = "SELECT my_cude FROM data";
    var readCube = (NpgsqlCube)(await command.ExecuteScalarAsync())!;
    Console.WriteLine($"Read cube: {readCube}");

Thanks to @kirkbrauer for contributing this feature!

## Various other changes

- OpenTelemetry tracing now also included by default for whenever a physical connection to database is open.
- Added support for `PGAPPNAME` environment variable. It's mapped to `ApplicationName` field of the connection string.
- Added support for SHA3 hash algorithms with SASL authentication. Previously, Npgsql falled back to SCRAM-SHA-256 if the certificate, provided by the database, had SHA3 signature algorithm.
- `NpgsqlConnection.Open` now wraps `SocketException` with `NpgsqlException` when hostname can't be resolved.
- Metrics names are now more aligned to the OpenTelemetry standard (see breaking change note below).
- The connection string now supports specifying `TargetSessionAttributes` when used with `NpgsqlDataSourceBuilder`. This means that code creating `NpgsqlDataSource` doesn't have to be aware that it's used with multiple hosts.
- The built-in geometry types (e.g. `NpgsqlBox`) can now be deconstructed. Thanks @ddas09 for contributing!
- The new `IDbTypeResolver` now allows remapping DbType values to arbitrary PostgreSQL types.

## Breaking changes

### .NET 6 is no longer supported

With .NET 6 being out of support since November 2024, Npgsql 10.0 also drops support for .NET 6. This change allows us to have a much better capability parity between different versions of .NET, while also removing hundreds lines of compatibility-only code and simplifying the codebase.

### `date` and `time` are now mapped to `DateOnly` and `TimeOnly`

The PostgreSQL `date` and `time` types are now read as .NET `DateOnly` and `TimeOnly`, instead of `DateTime` and `TimeSpan` by default, respectively. This affects non-generic read methods which return `object`, such as ExecuteScalarAsync and NpgsqlDataReader.GetValue; you can still read `DateTime` and `TimeSpan` via the generic GetFieldValue.

If your code relies on Npgsql returning `DateTime`/`TimeSpan` by default, and you are unable to either call `GetFieldValue()` or change your code to handle `DateOnly`/`TimeOnly` instead, then you can revert Npgsql's behavior to the pre-10.0 behavior. To do this, drop the LegacyDateAndTimeResolverFactory.cs into your project, and register it with your `NpgsqlDataSourceBuilder` as follows:

    NpgsqlDataSourceBuilder build = ...;
    builder.AddTypeInfoResolverFactory(new LegacyDateAndTimeResolverFactory());

Alternatively, if you're not yet using `NpgsqlDataSource`, register it with the global type mapper:

    NpgsqlConnection.GlobalTypeMapper.AddTypeInfoResolverFactory(new LegacyDateAndTimeResolverFactory());

### `cidr` is now mapped to `IPNetwork`

With .NET 6 no longer supported by Npgsql, the PostgreSQL `cidr` type is now mapped to `IPNetwork` by default instead of `NpgsqlCidr`. In addition, `NpgsqlCidr` is now obsolete and will be removed in the future.

### Tracing and metrics have been changed to align with the OpenTelemetry standard

Npgsql emits metrics and tracing data that provide various information about commands and connections. Since these were designed when the OpenTelemetry specifications were in an earlier stage, they did not align with current standard naming. Npgsql 10 changes metrics names and tracing span tags to better align with the standard, allowing Npgsql observability data to be tracked in dashboards just like other standards-conforming database drivers. If you already have a dashboard set up to consume Npgsql observability data, its configuration will need to change to accomodate the new naming.

### Cannot load library libgssapi_krb5.so.2 when Kerberos is not installed

Since Npgsql 10.0 defaults to trying GSSAPI session encryption, it may generate the following error on some Linux environments:

    Cannot load library libgssapi_krb5.so.2: cannot open shared object file: No such file or directory

Npgsql internally handles this and falls back to connecting without GSSAPI, so the error is harmless. You can specify `GSS Encryption Mode=Disable` to stop Npgsql from trying to use GSSAPI and remove the error.

### Only root CA certificate is used to validate TLS chain

While establishing TLS connection with PostgreSQL, Npgsql will now only use the provided root CA certificate to validate TLS chain instead of using it in addition to the system CA store. This behaviour aligns with libpq and prevents establishing unintended connections.

### COPY operation's `Timeout` property now treats `Timeout.InfiniteTimeSpan` as an infinite timeout instead of `TimeSpan.Zero`

This is in line with other .NET API (like `NetworkStream.ReadTimeout`), where `Timeout.InfiniteTimeSpan` and `Timeout.Infinite` are treated as infinite.

### `PostgresException.BatchCommand` is `null` by default

This prevents accidental leak of queries and parameters when exceptions are logged. To change this behavior you can set `IncludeFailedBatchedCommand` in connection string to `true`.

### NpgsqlConnection.BeginText{Import,Export}Async now return NpgsqlCopyTextReader instead of TextWriter

The methods to start a text import/export operation have been changed to return a more specific `NpgsqlCopyTextReader`, rather than a general `TextWriter`; this was done since `NpgsqlCopyTextReader` exposes some additional APIs to allow cancelling and setting the timeout on a COPY operation. Since `NpgsqlCopyTextReader` extends `TextWriter`, this is a binary breaking change only - recompiling against the new version of Npgsql should work without any source changes.

### NpgsqlParameter.DataTypeName now takes precedence over NpgsqlDbType

NpgsqlParameter allows configuring which PostgreSQL is sent to the database via several methods: DataTypeName (for a PostgreSQL type name as a string), NpgsqlDbType (PG-specific enum), or DbType (database-agnostic enum). Starting with Npgsql 10, setting DataTypeName takes precedence over NpgsqlDbType.

### JSON mutable DOM mappings (e.g. JsonNode, JsonArray...) now require EnableJsonTypes on NpgsqlSlimDataSourceBuilder

NativeAOT applications which use `NpgsqlSlimDataSourceBuilder` and make use of mutable JSON types (`JsonNode`, `JsonValue`...) now have to call `EnableJsonTypes()`. Previously, calling `EnableJsonDynamicTypes()` added these mappings.