DuckDB previews v2.0 with server mode, new SQL parser, 40x speedups

DuckDB's project blog previewed DuckDB v2.0, named "Cyanoptera" after a reddish-brown duck species, and due this fall. The team calls it a major version bump built from over 10,000 commits since v1.5 shipped in March, carrying a new SQL parser, a new default storage format, a reworked C API and a small number of deliberate breaking changes, alongside a large set of new features.
The headline addition is a native client/server mode. The quack extension, previously released as a preview, graduates to stable in v2.0: any DuckDB process can serve its databases over the network, and another DuckDB can attach and route queries to it with a new CONNECT statement, for example running CALL quack_serve(token = 'my_token') on the server and ATTACH 'quack:server.example.com' AS qk (TOKEN 'my_token') followed by CONNECT qk on the client. CONNECT also works against other databases through a new remote pushdown optimizer, so a statement like CONNECT 'postgres://localhost/mydb' sends SQL directly to PostgreSQL or MySQL instead of pulling tables over the wire. The team notes DuckDB has always had full MVCC and transaction isolation, and that the client/server pattern now lets multi-tenant, long-running deployments use that machinery. Third parties reportedly built their own standalone clients for the Quack protocol within weeks of its preview release.
VARIANT, introduced in v1.5, becomes fully supported end to end: shredded execution straight from storage, extraction pushdown into scans, shredded VARIANT reading and writing for Parquet, and a family of variant_* functions such as variant_type, variant_keys and variant_contains. The team plans to eventually back the regular JSON type with VARIANT so existing JSON workloads gain the same benefits without query changes, though it stresses this is not a firm commitment.
DuckDB also gets triggers for the first time: BEFORE and AFTER triggers, FOR EACH ROW and FOR EACH STATEMENT, transition tables via REFERENCING OLD/NEW TABLE, multiple triggers per event, RETURNING on triggered tables, and DROP TRIGGER, aimed at use cases like audit tables. The SQL dialect gains NEAREST joins for top-k similarity search, DML (INSERT, UPDATE, DELETE, COPY) inside CTEs, nested schemas, a new $variable syntax replacing getvariable(...), JSON mutation functions (json_set, json_insert, json_replace, json_remove), recursive CTEs with USING KEY aggregation backed by a rewritten recursive CTE engine, plus FETCH FIRST 2 ROWS ONLY, OVERLAY(), UNNEST in GROUP BY, and defined MERGE / UPDATE ... FROM semantics for multi-matched rows.
On performance, v2.0 introduces asynchronous I/O throughout the engine, starting with Parquet reads, then CSV and DuckDB's own file format, plus asynchronous Parquet writes and new MMAP and DIRECT_IO modes; the team says local storage benefits a little, but network storage sees the large gains. General query speed work includes pushing partial aggregates below joins, reusing redundant aggregations, aggregations spilling to disk when they outgrow memory, and a Windows CLI that is about 2.2x faster at multi-threaded result materialization. On a stated microbenchmark, a plain recursive CTE computing single-source reachability over a graph of one million edges runs about 40x faster in v2.0 than in the prior version. Row-group pruning now covers structs, lists, decimals, UUIDs, IN filters and function predicates, and query planning becomes partition-aware for lakehouse formats such as DuckLake, Iceberg and Hive-partitioned Parquet on S3.
The default storage format moves to v2.0.0, with buffer-managed ART indexes so large indexed tables open instantly instead of pinning indexes in memory, lazily loaded column metadata for faster opening of wide tables, DICT_FSST string compression enabled by default, more compact deletes, and stronger corruption validation on read. Finally, DuckDB replaces its PostgreSQL-derived parser with its own PEG-based parser, which lets extensions hook into the grammar to add new SQL syntax, gives more precise error locations, and introduces a dialect compatibility mode, set for example with SET dialect_compatibility_mode = 'spark'. The team says users should not notice anything from the parser swap, since it was designed to be compatible with the old one.
Key facts
- DuckDB v2.0, due this fall, is built from over 10,000 commits since v1.5 shipped in March
- A new client/server mode ships via the quack extension and a CONNECT statement; CONNECT can also push SQL directly to PostgreSQL and MySQL through a new remote pushdown optimizer
- New features include triggers, a fully end-to-end VARIANT type, a new PEG-based SQL parser replacing the PostgreSQL-derived one, and a new default storage format (v2.0.0) with buffer-managed indexes
- On a stated microbenchmark, a recursive CTE reachability query over one million edges runs about 40x faster in v2.0; the Windows CLI is about 2.2x faster at multi-threaded result materialization
- The team says the parser swap should be invisible to users because it was designed to stay compatible with the old parser
Why it matters
DuckDB calls this a major version bump that is not just ceremony: a new SQL parser, a new default storage format, a reworked C API and deliberate breaking changes ship alongside a large feature set built from over 10,000 commits since v1.5. After what the team frames as the year of the lakehouse, v2.0 is pitched as the start of DuckDB running as a server rather than only an in-process, single-user database, adding transactional, multi-tenant deployment as a first-class use case.
Who it affects
Teams already running DuckDB for local or embedded analytics gain a path to multi-tenant, long-running server deployments through the quack extension and CONNECT, plus direct query pushdown into PostgreSQL and MySQL. Users working with vector or embedding search benefit from NEAREST joins, those ingesting semi-structured logs benefit from the matured VARIANT type, and anyone querying object storage such as S3 benefits from the new asynchronous I/O layer and expanded row-group pruning.
How to use it
DuckDB v2.0 is previewed now and planned for release this fall. The client/server mode is used by running CALL quack_serve(token = '...') on a DuckDB server process and then ATTACH 'quack:...' ... CONNECT ... on a client; the same CONNECT statement can point at a PostgreSQL or MySQL connection string instead. The new parser adds a dialect compatibility mode, invoked with SET dialect_compatibility_mode = 'spark'. The post gives no pricing, licensing or availability details beyond the fall release window.
How solid is it
The preview comes from DuckDB's own project blog, describing features that are already merged and referenced by pull request number, with a fall release window but no specific date or year given. The quack extension underpins the new server mode and was already released as a preview before this post, with the team noting that third parties built independent clients for its protocol within weeks. The stated performance gains, including the 40x recursive-CTE figure and the 2.2x Windows CLI figure, come from the vendor's own benchmarks rather than independent measurement.
Risks and caveats
The release carries a new SQL parser and a new default storage format, both flagged by the team as deliberate breaking changes even though it says the parser swap should be invisible in practice. The post does not state whether databases written in the old storage format remain compatible after the upgrade to format v2.0.0. The 40x and 2.2x speedup figures come from a single vendor-run microbenchmark and a specific CLI workload respectively, not from broad independent benchmarking.
“You should not actually notice anything from the parser swap as we designed it to be compatible with the old one.”
— DuckDB project blog