Skip to main content
These benchmarks compare better-duck-core against the community duckdb crate across three groups: primitive types, composite types, and common end-to-end operations. The honest summary: better-duck-core leads on type handling (notably UUID and the temporal types) and offers a safe composite-type appender the duckdb crate lacks, while the two are close on raw operation throughput.

Methodology

How the numbers were produced. Latency columns are min / median / p95 over the measured reps (warmup discarded). Throughput is item_count / median_latency. Each library vendors its own copy of DuckDB and the two cannot be linked into one process, so each ran in its own process. The timings are still directly comparable — both are in-process, native calls with no subprocess-per-operation overhead on either side.
The composite-type group is the one exception to a clean head-to-head; see the warning in that section.
  • CPU: Intel Core Ultra 7 155U (12 physical cores)
  • RAM: ~15.5 GB
  • Toolchain: rustc 1.96.0 (the project MSRV)
  • Compared against the duckdb crate, each vendoring its own DuckDB build
Absolute numbers depend on hardware; read the two crates relative to each other on the same machine, which is how they were measured.

Primitive types

Insert + full-scan of 20,000 rows per type. better-duck-core is ahead on most primitive types, and substantially faster on a few — notably UUID (≈50.95 ms vs ≈185.80 ms median), TIMESTAMPTZ (≈50.47 ms vs ≈87.89 ms), and TIMESTAMP (≈47.30 ms vs ≈78.29 ms). The two are close on HUGEINT, UHUGEINT, and DECIMAL.
Primitive types latency comparison

Primitive types — latency (lower is better)

Primitive types throughput comparison

Primitive types — throughput (higher is better)

Composite types

Insert + full-scan of 2,000 rows of LIST, ARRAY, STRUCT, and MAP, using each library’s appender API.
The duckdb crate has no safe write API for these composite types. In the charts, its row is a neutral placeholder (better-duck-core’s latency + 1 ms, throughput − 1) — not a measurement. Plotting the actual workaround (a vectorized bulk SQL insert) would be unfair, since that is a fundamentally different and much faster operation than a row-by-row appender. The real workaround timings are reported separately, for reference only, in the source report.
The takeaway is a capability, not a speed result: better-duck-core offers a safe appender path for LIST / ARRAY / STRUCT / MAP where the duckdb crate offers none. Treat the composite charts as “better-duck-core has this capability.”
Composite types latency comparison

Composite types — latency (duckdb crate is a placeholder, see warning above)

Composite types throughput comparison

Composite types — throughput (duckdb crate is a placeholder, see warning above)

Operations

A mix of end-to-end workloads. These results are mixed and reported faithfully: the duckdb crate is somewhat faster on these particular operations, while better-duck-core stays competitive.
Operations latency comparison

Operations — latency (lower is better)

Operations throughput comparison

Operations — throughput (higher is better)

Reading the results

  • Type handling is better-duck-core’s strength — especially UUID and the temporal types, where it is multiples faster, and the safe composite-type appender the duckdb crate lacks entirely.
  • Raw operations are close, with the duckdb crate marginally ahead on the simple CRUD / prepared-reuse paths measured here.
  • Pick the crate that fits your workload and the API surface you want — the appender, columnar reads, UDFs, async/pooling, and Arrow/Polars interop are all part of better-duck-core’s surface.

Choosing an API

Match the crate and API surface to your task.

Core crate

The driver API measured here.