DuckDB.NET 1.5
This page lists the changes in DuckDB.NET 1.5 releases, newest first. For other versions, see Release Notes.
1.5.6.1
Released 2026-10-15 (NuGet, changes since 1.5.6). Built on DuckDB v1.5.6.
New features
- Read a TIME column as
TimeSpan. - Read FLOAT as
double, DOUBLE asfloat, and both asdecimal, in columns, list items, maps and structs. - Read HUGEINT and UHUGEINT columns as
DuckDBHugeIntandDuckDBUHugeIntwithGetFieldValueandGetProviderSpecificValue. - The mapped appender now accepts
DuckDBDateOnlyandDuckDBTimeOnlyproperties, and scalar functions accept them as parameters and results. BigIntegervalues can now be bound and appended to UHUGEINT columns as unsigned values, including through the mapped appender.- A table function over an array now uses the length of the array as its cardinality hint when none is given.
Performance
These numbers were measured against 1.5.6 on .NET 10 with a million rows. The gains are in moving values between DuckDB and .NET, so bulk appends, reading large results and queries that call C# functions benefit most. Queries dominated by DuckDB's own work change little.
- Reading numbers and booleans through
GetInt32,GetFieldValue<T>and the other typed getters is 3.5 to 6 times faster. Reading an integer column asdoubleis 12 times faster. - Reading short strings is up to 1.35 times faster.
- Reading dates, times and timestamps is 3 to 12 times faster. Appending a
DateTimeis 14 to 26 times faster. - UUID, DECIMAL and HUGEINT reads are 1.7 to 7 times faster.
- Typed scalar functions are 5 to 8 times faster, and 1.6 times faster with a string argument.
- Table functions are 2.5 to 6 times faster.
- With projection pushdown, the columns a query does not read are no longer computed. A query that reads one column of a four-column table function is about 6 times faster, and the gain grows with the number of unread columns.
- LIST, STRUCT and MAP columns are read into .NET types up to 6 times faster.
- Appending
BigInteger, lists, strings, C# enums and through the mapped appender is 1.3 to 4 times faster. Numbers are 1.2 to 1.4 times faster. Decimals of up to 18 digits are 1.3 to 2 times faster depending on the CPU, and wider decimals more than twice as fast.
Memory
These numbers are per million rows, against 1.5.6.
- Appending no longer allocates for each value. 1.5.6 allocated about 750 bytes for every
DateTime(2.9 GB for four TIMESTAMP columns), 756 MB for a record of mixed types in the mapped appender, 211 MB for lists ofint?, 188 MB for C# enums and up to 315 MB forBigInteger. Each is now about 0.1 MB. - Scalar functions with nullable arguments or results, and table functions over structs or rows with nullable columns, no longer allocate for each row. They allocated 21 to 47 MB in 1.5.6 and now about 0.1 MB.
- An integer read as
doubleno longer allocates (375 MB for eight million values in 1.5.6). A DECIMAL wider than 18 digits is read without aBigInteger(107 MB, now none). A large HUGEINT read asBigIntegerallocates a third as much. - LIST, STRUCT and MAP reads allocate up to 60% less, and
GetValues9 to 17% less.
Fixes
- A
Read()after the end of a streaming result, and the firstRead()of an empty streaming result, no longer throw (#358). - Reading an ENUM column as a type other than
stringno longer reads past the stored value. - Reading a BIT column as an unsupported type throws
InvalidCastExceptioninstead of ending the process with a stack overflow. - Negative intervals can be read as
TimeSpan, bound and appended. - A TIMETZ read as
DateTimeOffsetno longer throws for a time earlier in the day than its positive offset. - -2^127 is accepted as a HUGEINT value, and the HUGEINT limits no longer fail under cultures with another minus sign.
- A decimal parameter is sent with the exact number of its digits. Before, 1000 was sent as DECIMAL(3,0).
- A list parameter that DuckDB cannot build is refused instead of crashing the process.
- The exception of a scalar function that throws in WHERE or HAVING is now the
InnerExceptionof the error. - A table function projection that calls a constructor (a record or a tuple) is refused with a clear message instead of a
NullReferenceException. - The mapped appender disposes its appender when validation fails.
DuckDBClientFactory.CanCreateCommandBuilderandCanCreateDataAdapterreturnfalseinstead of throwing.
Behavior changes
- Appending a decimal too wide for its column throws instead of storing a value the column cannot hold.
- A
TimeSpanparameter where DuckDB cannot infer the type is bound as an INTERVAL instead of as text. DeclareDbType.Timeto bind it as a time. - Looking up a missing parameter by name through
DbParameterCollectionthrowsIndexOutOfRangeException, as the typed indexer does. - A TIMETZ read as
DateTimeOffsetis placed on 0001-01-02 instead of 0001-01-01. - A
BigIntegerparameter where DuckDB cannot infer the type is bound as HUGEINT if it fits, as UHUGEINT up to 2^128 - 1 and as BIGNUM beyond. Before, values outside the HUGEINT range threw.
Bindings
- New features:
DuckDBHugeInt.ToInt128andDuckDBUHugeInt.ToUInt128.- Equality without boxing (
IEquatable<T>) forDuckDBDateOnly,DuckDBTimeOnly,DuckDBTimestamp,DuckDBIntervalandDuckDBTimeTz. - Bindings for
duckdb_scalar_function_set_bind_data_copyandduckdb_unsafe_vector_assign_string_element_len.
- Performance: creating a
DuckDBHugeIntorDuckDBUHugeIntfrom aBigIntegeris faster and no longer allocates. - Fixes:
DuckDBIntervalreads and writes negative days and microseconds.DuckDBHugeIntaccepts -2^127, and its limits no longer fail under cultures with another minus sign.
1.5.6
Released 2026-09-28 (NuGet, changes since 1.5.5). Built on DuckDB v1.5.6.
New features
- Typed properties for 24 DuckDB configuration options on
DuckDBConnectionStringBuilder. - Read DECIMAL values that do not fit
System.DecimalasBigIntegerorDuckDBDecimal. - Bind
BigIntegerparameters wider than 128 bits to BIGNUM (formerly VARINT) columns.
Fixes
- Fixed possible data loss on Linux and macOS when a reader opened with
CommandBehavior.CloseConnectionclosed the last connection to a file database (#357). - Errors in later chunks of a streaming result are now thrown instead of silently ending the result, in
DuckDBDataReaderand the Arrow stream (#356). - Fixed a memory leak where results skipped with
NextResultwere never released. - Fixed incomplete appender rows being written with uninitialized values (#355).
- Fixed ARRAY values shifted by one row after a NULL array in the appender.
- Fixed the appender writing to freed memory when a list of arrays grows.
- Fixed table functions returning no rows after the first iteration of a recursive CTE (#348).
Behavior changes
GetFieldValue<object>now returns the same value asGetValue.- Reading a LIST or MAP into an untyped target (
object,ArrayList,List<object>, or aDictionarywithobjectkeys or values) throwsInvalidCastException. UseGetValueinstead. - A failed
ExecuteReaderwithCommandBehavior.CloseConnectionnow closes the connection, as in Npgsql. - Moving on from an incomplete appender row discards it and faults the appender: the next
CreateRoworAppendRowthrows, and rows completed before it are still written.Close,DisposeandCleardiscard an incomplete row without an error. - A blob
StreamfromGetStreamis valid only until the reader moves to the next result set.
Bindings
- Added a binding for
duckdb_create_bignumand theDuckDBBignumstruct.
1.5.5
Released 2026-07-26 (NuGet, changes since 1.5.3). Built on DuckDB v1.5.5.
New features
- Apache Arrow result streaming through
DuckDBCommand.ExecuteArrowStreamandExecuteArrowBatchesAsync(#26). See Apache Arrow. - A new allocation-free
DuckDBAppender.AppendRowAPI with reusable rows. - Support for
byte[]columns inDuckDBAppenderMap.
Fixes
- Fixed
IndexOutOfRangeExceptionwhen accessing reader metadata after exhausting the result set (#332).
Performance
- Reduced allocations in parameter binding and same-type object reads.
Bindings
- Added bindings for the Arrow C Data Interface (
duckdb_to_arrow_schema,duckdb_data_chunk_to_arrow,duckdb_result_get_arrow_options). - Added bindings for error data (
duckdb_appender_error_data,duckdb_error_data_error_type).
1.5.3
Released 2026-05-24 (NuGet, changes since 1.5.2). Built on DuckDB v1.5.3.
New features
- Improved support for binding
ICollectionparameters (#326).
Fixes
- Fixed
ObjectDisposedExceptionin the enum appender (#327).
1.5.2
Released 2026-04-24 (NuGet, changes since 1.5.0). Built on DuckDB v1.5.2.
New features
- Projection pushdown for table functions.
- Estimated cardinality hints for table functions.
IList<T>column support in table functions.
1.5.0
Released 2026-03-10 (NuGet, changes since 1.4.4). Built on DuckDB v1.5.0.
New features
- High-level scalar function API. See Scalar Functions.
- High-level table function API. See Table Functions.
- Named parameters for table functions through the
[Named]attribute. - NULL handling for scalar functions is inferred from nullable parameter types (
int?,string?). - An appender
Clear()method to discard in-progress rows.
Performance
- Vector readers are reused across chunks instead of being recreated for each chunk.
- Migrated from
DllImporttoLibraryImportwith source-generated P/Invoke. - Enum dictionary lookups in
EnumVectorDataReaderare cached. - Nullable
GetValue<T>uses expression trees to avoid boxing. SuppressGCTransitionon trivial native calls.AggressiveInliningon hot-path methods.- Appender value writes are split by struct and class to avoid boxing.
Behavior changes
- Dropped
netstandard2.0andnet6.0. The packages now targetnet8.0and later.
Bindings
- Custom string marshallers for correct handling of DuckDB string ownership.