Products#Benchmark#Data analysis

DuckDB 2.0.0 LTS ships a new storage format older versions cannot read

DuckDB 2.0.0 LTS landed October 21, supported to October 2027. New files use storage format 69, which pre-2.0 versions cannot open.

A duck silhouette formed from rows of small data marks and dashes on a yellow field, wings spread

DuckDB is an embedded analytical database that runs in-process by default, with no separate server: the data lives in one file or in memory, and a columnar engine runs SQL over it. The DuckDB team released 2.0.0 LTS on October 21, 2026, codenamed Cinnamon Teal, with GitHub timestamping the release at 12:49 UTC that day. Every database file the new version creates uses storage format 69 by default, and DuckDB versions before 2.0 cannot open those files. Community support runs until at least October 2027.

Key points

  • Support window: the release post says support runs until at least October 2027, and the release calendar lists end of life as 2027-10-22. The previous LTS, 1.4, ends on 2026-11-17, and 1.5 was extended to 2027-03-01. The calendar lists 2.0.1 for 2026-11-18, with a note that dates can slip.
  • The break runs one way. Files created by 2.0 use storage version 69, and files written by 1.x carry version 68 or lower. Version 2.0 still reads and writes old files and keeps their storage version, so the risk sits only on files it creates or saves.
  • Server mode: the Quack protocol was announced on 2026-05-12, and 2.0 ships a polished version with the new CONNECT statement plus duckdb -serve and duckdb -connect. The server listens on localhost only by default.

Background

DuckDB billed 1.0 as a stability and backward-compatibility release; 2.0 is first a feature release. The groundwork came in steps: 1.5 introduced the VARIANT type, and the PEG parser arrived as an opt-in feature in 1.5. The Quack protocol was announced on 2026-05-12, and the release post says it arrived in 1.5.3 in May. The May announcement promised the first production release together with DuckDB v2.0, and this is that release.

Three maintenance lines are now open at once. 2.0 is the LTS; 1.4 runs to November 2026; 1.5 was extended to March 2027, which the team says effectively makes it an LTS release too, so upgraders have time to test. The CLI and Python client were available on day one, while the Go, R and Java clients and some extensions need a few days for extra changes and review rounds.

The codename appears in two spellings, and they do not conflict. The release post says Cinnamon Teal; the GitHub release title says Cyanoptera. Both name the same species, Spatula cyanoptera, and both pages say so.

The acquisition is a separate matter. InfoQ reported on October 17 that Amazon had announced the acquisition of DuckLabs, with DuckDB, DuckLake and Quack staying MIT-licensed under the non-profit DuckDB Foundation. We checked the October 21 announcement and it never mentions Amazon or AWS, so this does not count as the first release after the acquisition.

The site has covered MotherDuck’s official DuckDB MCP server (DuckDB / MotherDuck MCP), which lets agents run analytical SQL against local files, S3 or MotherDuck. Agent mode in 2.0 addresses the command-line side of the same workflow, and the two can be stacked.

Migration checklist

The feature list is long. The parts most likely to touch daily work start with asynchronous I/O for Parquet, CSV and DuckDB’s native format: reads are issued in the background with several requests in flight, the I/O layer scales independently of query processing, and remote object storage gains the most. VARIANT was already native in 1.5; what 2.0 adds is full integration, in the release post’s words: “DuckDB 1.5 already introduced VARIANT, but DuckDB 2.0 fully integrates it.” The engine detects common structure and shreds it, end to end through Parquet reads and writes.

On the SQL side, 2.0 adds triggers: BEFORE and AFTER, FOR EACH ROW and FOR EACH STATEMENT, transition tables via REFERENCING OLD/NEW TABLE, RETURNING on triggered tables, and DROP TRIGGER. The docs also list combinations that do not work yet, such as BEFORE with FOR EACH ROW and UPDATE with FOR EACH ROW. The dialect gains $variable shorthand, INSERT/UPDATE/DELETE/COPY inside CTEs, NEAREST similarity joins and nested schemas. Extensions can now come from self-hosted repositories whose RSA public keys are pinned into the repository definition: at CREATE EXTENSION REPOSITORY time, DuckDB fetches the keys, pins them, and prints each key’s SHA-256 fingerprint for an out-of-band check. The revamped C API v2 is more capable, and the team says plainly it is not stable yet and wants field testing first. ICU is gone: the extension now implements timezones, calendars and collations from IANA data compressed to about 45 kB. By the release post’s count, the version carries close to 20,000 commits since 1.5.

The breaking changes are few, and each one lands on a real deployment:

ChangeBehavior in 2.0What to do
StorageNew files default to version 69; 1.5.6 reads 64 to 68Pin an older storage version where older readers must work (below)
ParserThe PEG parser becomes the defaultInstall the legacy_parser extension and run SET enable_legacy_parser = true
LambdaSingle-arrow x -> x + 1 is off by defaultWrite lambda x: x + 1, or set lambda_syntax = 'enable_single_arrow' temporarily
CompilerBuilding extensions now needs C++17Upgrade the toolchain
PlatformCommunity extensions no longer build for macOS x86_642.1 drops osx_amd64; move to arm64 first
BuildThe amalgamation single-file build is deprecatedUse a normal build
C API v2More capable, interface not yet stableTry it and report problems

The storage escape hatch is more specific than the headline suggests. The migration guide shows the exact failure: IO Error: Trying to read a database file with version number 69, but we can only read versions between 64 and 68. To keep older readers working, create files with an explicit storage version: duckdb -storage-version v1.2.0 my_database.duckdb on the command line, ATTACH 'file.db' (STORAGE_VERSION 'v1.2.0') in SQL, or the storage_compatibility_version setting in a client. To move an existing database up to 69, the documented path is EXPORT DATABASE on the old version, then IMPORT DATABASE on 2.0. The guide also warns that in a deployment with many processes sharing one file, a single 2.0 process writing the new format makes the file unreadable to every older process, so the whole chain has to move together.

The parser swap is meant to be invisible: the new parser is designed to be compatible with the old one, and the team asks for an issue if a query that parsed before now fails. The single-arrow switch is a temporary bridge; 2.1 removes the flag and the syntax.

What the tests show

Third-party measurements so far come from preview builds. Javier de la Torre at LakehouseBox published a comparison on October 14 using 2.0.0.dev2610011535 against 1.5.6, over the same TPC-H SF10 data in Apache Iceberg tables stored in Nuremberg:

Scenario1.5.62.0 previewResult
Nuremberg, same data center, cold, 22 queries105.9 s62.7 s1.69x total, 1.93x geomean
Madrid over home fiber, cold270.8 s260.3 s1.04x
Madrid, warm, same connection13.6 s19.8 s46% slower, 170 MB re-fetched
Iceberg write of lineitem, 60M rows409 files4 files8-table load 108.5 s to 84.6 s

The data-center gain comes from overlapping many small range requests: the same bytes arrived in 9,346 HTTP GETs instead of 6,126, hiding latency. Over a home connection the bottleneck moves back to bandwidth, so the cold pass is only 4% faster, and the warm pass is slower because the preview re-fetched 170 MB on repeat runs. The author also found a pruning regression: a table sorted along a Hilbert curve cost 9.4 MiB in 8 GETs on 1.5.6, while the preview read the whole 281 MB table. They filed duckdb#27247 on October 14, the fix merged into the 2.0 branch on October 18, and a re-measurement on October 20 with the newest preview read 11.5 MiB in 12 GETs. The post is explicit that these numbers come from preview builds and that a full rerun waits for 2.0.0 final.

Hacker News supplies the other side. When we looked on 2026-10-22, the submission had 375 points and 49 comments. RobinL reports that 2.0 is much faster on high-core EC2 machines, for computation as well as S3 reads, with utilization holding near 100% up to about 128 to 192 vCPUs where it used to top out near 64; that let them run Splink over 1 billion records and 10 billion comparisons in 10 minutes. In the same thread he cautions about over-parallelizing, where wall time grows past some core count. gopalv points at AWS Nitro and suspects CPU steal when every core is busy. llimllib warns that duckdb-wasm range queries over HTTP pull far too much data unless builtin_httpfs is disabled, and tomjakubowski replies that the same symptom — read_parquet firing tiny range requests at S3 to load Parquet footers — is what they had spent the week debugging.

InfoQ’s August 25 analysis, by Olimpiu Pop, describes what the release actually adds: any DuckDB instance can run as a daemon accepting network connections, and a session can ATTACH external engines such as PostgreSQL and MySQL with query pushdown. The piece carries no quantitative benchmark. Its “more than 10,000 commits” figure follows the August preview; the October release post says close to 20,000.

On the Chinese side, a QUASA editorial from October 20 never mentions 2.0 or LTS but draws the selection boundary clearly: embedding DuckDB in an application that serves an API still leaves the app to schedule concurrent requests, cap expensive queries, handle writes and publish results, and to decide how the front door scales. Latency from a single-user notebook says nothing about queueing and tail latency when requests arrive together.

Vendor figures are a separate category. A DuckDB post on October 16 ran TPC-H at SF1000 on NVIDIA Vera: an 88-core, single-socket Vera scored 3,073,292.99 against 2,109,782.19 on a 96-core Xeon 6, which the team calls a 46% advantage. The run was not audited through the official TPC-H process, only one Vera socket was used, and the authors themselves say both results would merely have a chance at the SF1000 top three.

Our take

For teams that embed DuckDB in a product or run data pipelines on it, 2.0 belongs on the upgrade plan, provided the storage change is treated as a real migration. A single-machine upgrade is usually straightforward; the case that hurts is a mixed-version deployment, where one 2.0 process writing a database file locks out every 1.x process sharing it. Either move the whole chain at once or pin STORAGE_VERSION wherever shared files are written. The official advice is unusually direct for a release post: test on a shadow system, and if the workload is mission-critical, wait for the first patch release in November.

Read the agent-mode number as what it measures. The 59% is DuckDB output tokens the model read, 123.6k down to 50.8k in the team’s experiment. The same post says that saving is about 0.5% of total input, because each turn re-reads the system prompt; runtime and total cost did not improve, and the run took slightly more turns, 237 against 224. Calling it “half the cost” misreads it.

Quack’s promotion changes the deployment shape, and its ecosystem is still forming. HN commenter nicoritschel says they already run the alpha in production as a centralized analytics server for a small organization, and that Quack client support is very limited, so they route existing BI tools through the Postgres wire protocol or Arrow Flight instead. The security defaults are conservative: the server listens on localhost, allow_other_hostname is documented as testing-only, and cross-machine access belongs behind a TLS-terminating reverse proxy.

What is still unknown: there is no third-party benchmark of 2.0.0 final, the lakehouse numbers all come from mid-October builds, and the pruning fix landed days before release. The Vera result is the vendor’s own, unaudited. The only way to know how 2.0 behaves on your workload is to run it.

How to try it

The shortest path is the CLI, a version check, then a server and client pair:

curl https://install.duckdb.org | bash
duckdb -c "SELECT version();"

Start a server in one session:

duckdb -serve

Connect from another terminal:

duckdb -connect

To write a database that DuckDB 1.5 can still open, pin the storage version at creation:

duckdb -storage-version v1.5.6 legacy.duckdb

Add -agent to see agent-mode output by hand, or -no-agent to force it off. A script that sets no agent environment variable can still opt in with DUCKDB_AGENT_MODE=1.

What to watch

The release calendar puts 2.0.1 on 2026-11-18, with the same caveat that planned dates can slip; that is the patch release the team tells mission-critical users to wait for. The 2.1 removal list is already published: the single-arrow lambda goes away with its flag, and macOS x86_64 loses support. C API v2 becomes stable only after a round of outside testing. LakehouseBox says it will rerun the full benchmark on 2.0.0 final, including the spatial queries now that pruning is fixed, and that run will show how much of the preview verdict survives.