Announcing an ADBC driver for Quack
Last week, the team behind DuckDB announced Quack, a native client-server protocol for DuckDB. Today we’re happy to release a public preview of an ADBC driver for Quack. You can install it now with dbc:
dbc install --pre quack
The driver is still a work in progress, but already supports queries, bulk ingest, metadata/catalog operations (GetObjects), and transactions.
What is Quack? Why would I use it?
Quack is a client-server protocol for DuckDB. Instead of executing DuckDB queries locally against locally stored data, Quack lets you connect to a remote DuckDB instance, and your queries execute there against remotely stored data. If you’ve been using one of the various projects that wrap DuckDB in an Arrow Flight SQL server (another example of a client-server protocol), or if you’ve been looking for a scalable way to concurrently insert into a single DuckDB database, consider pairing a Quack server with this ADBC driver.
You can read more in DuckDB’s announcement.
How do I use the ADBC driver for Quack?
Once installed (using the dbc install command above), the Quack driver works like any other ADBC driver. Here’s a quick example in Python. If you don’t already have a Quack server running, follow the Starting a Server instructions in the Quack documentation. To try this on your local machine, install DuckDB 1.5.3 or higher, start the DuckDB CLI in your terminal, and run:
CALL quack_serve('quack:localhost');
Note the listen_url and auth_token that DuckDB prints. Use these to replace the host, port, and quack-secret in the script below:
# /// script
# requires-python = ">=3.10"
# dependencies = ["adbc-driver-manager>=1.9.0", "pyarrow>=20.0.0"]
# ///
from adbc_driver_manager import dbapi
with (
dbapi.connect("quack://localhost:9494/?token=quack-secret") as con,
con.cursor() as cursor,
):
cursor.execute("FROM range(0, 100, 2)")
table = cursor.fetch_arrow_table()
print(table)
Save the updated script to script.py and run it:
uv run script.py
You should see this output:
pyarrow.Table
range: int64
----
range: [[0,2,4,6,8,...,90,92,94,96,98]]
How does the driver work?
Internally, the driver embeds DuckDB and the Quack extension, though this isn’t exposed to you. DuckDB is designed to be embeddable, and leaning on that gives us strong performance and guaranteed compatibility out of the gate. Bundling the necessary extensions into the driver also means there’s nothing extra to install or load. We’re still weighing the tradeoffs of this approach, and future versions of the driver may implement the protocol from scratch instead.
Because DuckDB is itself written in C++, embedding it meant writing the driver in C++ as well. It’s not the first ADBC driver written in C++—the PostgreSQL and SQLite drivers are too—but for new drivers without a similar constraint, we generally recommend Rust or Go for the developer experience. The faster, more predictable build cycles in those toolchains make a real difference, especially in agent-assisted workflows; spending an afternoon back in the world of “it’s compiling!” was a fun throwback, but not one we’d sign up for by default. To make Rust and Go the path of least resistance, we maintain driver base frameworks for both Rust and Go, as well as a Rust driver template. We don’t currently provide similar scaffolding for C++.
What’s next?
We’ll keep improving the driver, as with all of our drivers and projects. You can file feature requests and bug reports in the adbc-drivers/quack repository on GitHub, start a discussion in the adbc-drivers organization, or join the Columnar Community Slack.