Data

DuckDB 2.0: The Database That Stops Being Just a Library

DuckDB 2-0

Quack reverses years of in-process doctrine. Its defaults are safe because they bind to localhost, the LTS label promises a year of patches, and the 59% agent-mode figure measures tokens, not cost.

DuckDB 2.0.0 landed on GitHub at 12:49:12 UTC on 21 October. The Python package appeared on PyPI 86 seconds later. Between the previous feature release and this one sit 19,355 commits, close enough to the “almost 20,000” the project claims in its announcement, and large enough to make this the biggest release in DuckDB’s history.

The reception was oddly quiet. The Hacker News submission of the blog post, posted at 14:01 UTC, had 20 points and three comments when checked. The loud thread had come eleven days earlier, when MotherDuck published a performance post: 222 points and 64 comments for a release nobody could download yet.

DuckDB 2.0 is the release where a database that spent years arguing you do not need a client-server split shipped one, where an embedded tool grew a security model that whoever deploys it has to configure, and where the interface changed for a user that is not human. Most coverage lists the features. This article looks at the three admissions underneath them.

What actually shipped

The announcement post calls 2.0.0 an LTS release and the biggest feature release the project has done. The GitHub tag is not marked prerelease or draft, and the repository stood at 42,342 stars at the time of writing.

The two codenames refer to the same bird. The blog says “Cinnamon Teal” and the GitHub release says “Cyanoptera,” which are the English common name and the species epithet. A citation using only one is incomplete.

The headline list is: a polished Quack protocol, asynchronous I/O, first-class VARIANT, CLI agent mode, triggers, an extensible SQL parser, C API v2 and extension repositories. Three of those eight are architectural rather than user-facing, which suggests a platform release.

Confirming you have it is less trivial than usual. On launch day the CLI and Python packages were at 2.0.0 while the install page still listed 1.5.x for C/C++, Java, R, Rust, Wasm and ODBC. The announcement said Go, R and Java would follow within days. If your pipeline is built on one of those bindings, “DuckDB 2.0 is out” and “your DuckDB is 2.0” are different statements.

Quack reverses DuckDB’s in-process stance

The most common launch-day error is treating Quack as new in 2.0. It was announced on 12 May 2026 and shipped as a core extension in 1.5.3. What 2.0 adds is the production packaging: auto-install, a CONNECT statement, -serve and -connect flags in the CLI, a remote pushdown optimizer, and documentation that treats the protocol as a supported surface rather than an experiment.

The reversal still matters. The May post walks through why in-process execution was the right default, then says the team “bit the bullet, eventually, finally” because users kept building workarounds anyway. That is an unusually candid admission for a database project, and it explains why this release exists.

Quack uses HTTP as transport and a serialization format called application/duckdb that reuses DuckDB’s write-ahead log primitives. The default port is 9494. Requests are client-driven and take a single round trip per query once connected, and multiple clients can write to the same database concurrently, something in-process DuckDB could never do.

The project’s own benchmarks, run in May on two m8g.2xlarge instances in one availability zone with about 0.28 ms of ping, put Quack at 4.94 seconds to transfer 60 million TPC-H lineitem rows. Arrow Flight SQL took 17.40 seconds; the PostgreSQL protocol took 158.37. Small-write throughput peaked at 5,434 transactions per second at eight threads against 4,320 for PostgreSQL, and the post concedes that past eight threads, DuckDB itself becomes the ceiling.

Quack allows concurrent writers, but the benchmarks do not show it replacing Postgres. They compare protocols with each other, not with embedded DuckDB on the same workload, and nobody has published the latency tax of going remote.

Quack’s security defaults

Quack generates a random authentication token at startup that the client must present. The server binds to localhost by default. TLS is off by default, on the argument that wrapping loopback traffic in TLS is “a bit silly.” For non-local connections the client assumes SSL is enabled, and the project recommends terminating TLS at nginx or a comparable proxy rather than exposing DuckDB directly.

The default that matters most is authorization. Quack ships with no restrictions: the default authorization function “just says ‘yes’ to everything.” Anyone holding the token can run any SQL, including writes. Both authentication and authorization are replaceable callbacks, which can even be plain SQL macros. That is extensible, but per-user and per-tenant policy is code you write, not something the server gives you.

2.0 adds an allow_other_hostname setting that the announcement explicitly scopes to testing only. Read the defaults as a threat model: a token per server plus a localhost bind is reasonable for a sidecar process and wrong for a shared internal service without a proxy and a custom authorization callback. A token identifies a caller; it does not grant or limit permissions.

DuckDB as a client

Alongside Quack, 2.0 extends CONNECT for remote SQL databases, including PostgreSQL and MySQL. DuckDB talking to Postgres is an ETL and federation feature. Quack is DuckDB talking to DuckDB, and it is about concurrency and protocol efficiency. They are different capabilities, and shipping them together led many summaries to merge them.

Federation is not new either: DuckDB’s PostgreSQL scanner has supported parallel reads in some cases for a while, so the competitive claim against Postgres rests on framing and parallelism.

Agent mode and the 59% figure

On 9 October the project documented agent mode for the CLI: when it detects an agent, it emits Markdown tables, truncation notices and structured JSON errors, and stops runaway queries. Detection is deliberately conservative: an environment variable, a non-TTY stdout, and no explicit format flag, so ordinary scripts do not accidentally get agent formatting.

Claude Code answered 22 TPC-H questions at scale factor 100, three runs each with and without agent mode: 132 runs, all correct.

Tokens read fell from 123,600 to 50,800, a 59% reduction. That is the number that travelled. The post states the caveats just as plainly: the saving is about 0.5% of total input tokens because the system prompt dominates, cost and runtime were unchanged, and agent-mode runs took slightly more turns, 237 against 224.

The headline that fits the data is “less context burned on table formatting, same bill.” That is still worth having, since fewer tokens spent on pipe characters leaves more room for the actual question. But anyone quoting 59% as a cost saving is quoting a number the project did not claim, and the raw report is public if you want to check the method.

The breakage ledger

LTS does not guarantee compatibility. The most important operational fact in this release is that the storage format change is one way: pre-2.0 binaries cannot read 2.0 files, while 2.0 reads older files. Once a persistent database is opened by 2.0, going back means restoring a backup.

ICU is gone from the core build. Time zones, calendars and collations moved into an icu extension of roughly 45 kB, so installs that relied on it implicitly now need an explicit step. The parser is PEG by default, with a legacy_parser escape hatch for unusual SQL. Integer division and modulo by zero now raise errors instead of returning a value, which can convert a silent zero into a failed job overnight.

The rest of the list is smaller: single-arrow lambdas are off by default and scheduled for removal in 2.1, S3 URL parameters are disabled by default, the identifier-case setting changed type, some profiling and HTTP-logging settings were removed, the amalgamation build is deprecated, and C++17 with Clang is the default toolchain. macOS on Intel begins a phase-out that ends in 2.1.

What breaks in DuckDB 2.0, and the first move for each
Change Who breaks Mitigation
New storage format, one-way Anyone upgrading a persistent database file Export first; keep a 1.5 binary for rollback
ICU removed from core Collation and time-zone-heavy queries Install the icu extension explicitly
PEG parser is default Unusual or dialect-specific SQL Enable legacy_parser while porting
Divide and modulo by zero error Pipelines relying on a silent 0 Add NULLIF or CASE guards
Single-arrow lambdas off Older lambda-heavy SQL Rewrite before 2.1
S3 URL parameters off Configs passing credentials in URLs Move to settings or secrets
C API v2 Extension authors Port against v2 headers
macOS x86_64 phase-out Intel Mac CI Plan arm64 runners before 2.1

Source: the 2.0.0 announcement.

What LTS means here

DuckDB 2.0.0 is supported until 22 October 2027, according to the project’s release calendar. The label buys a year of patches.

Support for the previous LTS line, 1.4, runs to 17 November 2026, roughly a month after 2.0 shipped. The non-LTS 1.5 line was extended to March 2027, which softens the pressure for teams that moved to 1.5 recently. The first patch, 2.0.1, is scheduled for 18 November 2026, which makes it a more sensible target for production than launch week.

Put together, 1.4 users have about a month to migrate off a line that ends the day before the first 2.0 patch lands. That is not a lot of room for a release that changes the storage format.

Ecosystem, ownership and the missing independent test

DuckLabs, the company behind DuckDB, announced in August that it would become part of AWS, expected effective in early September 2026, with DuckDB, DuckLake and Quack staying MIT-licensed and the nonprofit DuckDB Foundation continuing stewardship. At announcement the company claimed more than three million downloads a day and about 30 employees in Amsterdam.

Two things follow. Extension repositories, new in 2.0, are the technical half of a policy DuckLabs said it wanted: letting DuckDB run extensions signed by other developers and organisations. The trust details were still described as forthcoming. And platform teams will now read every future DuckDB decision as an AWS signal, whether or not it is one.

On performance, MotherDuck’s pre-launch post claims VARIANT is up to six times faster than JSON stored as text, recursive CTEs up to 90 times faster, and asynchronous I/O 2.4 times faster on S3, all measured against 1.5.5. Those are vendor-authored, pre-release and benchmark-specific, so treat them as directional claims from a vendor, not independent verification.

Nothing in this release has been independently reproduced yet. The Quack numbers, the agent-mode experiment and the MotherDuck speedups all come from parties with an interest in the result. That does not make them wrong, only unconfirmed.

What to do and what to watch

If you keep persistent DuckDB files in production, export before you upgrade and keep a 1.5 binary available. If you deploy Quack anywhere other than localhost, write the authorization callback before you write the client, and put TLS in front of it. If you run 1.4, start the migration now rather than in November.

For everyone else, the open question is whether the project’s default posture (permissive, local, token-only) survives the shared-service deployments its users are about to build. The protocol is polished, while authorization policy is left to a callback you write.

Watch the 17 November end of 1.4 support, the 18 November 2.0.1 patch, and the point at which the Go, R, Java and Rust bindings reach 2.0.0. Also watch for the first independent Quack benchmark, which turns “4.94 seconds” from a vendor claim into a measurement.

Leave a Comment