DuckDB
Tested with: DuckDB 1.5 on Databasezy · zb CLI 0.1
DuckDB is an in-process analytical SQL database: columnar storage, vectorised execution and a rich SQL dialect for aggregations, window functions and ad-hoc analysis. On Databasezy one DuckDB database file is served over HTTPS so a team can share it.
Overview
Section titled “Overview”DuckDB has no network server of its own, so each instance runs zb-duckdb-server, a small open-source HTTP server
around an embedded DuckDB database file. You send SQL as JSON to POST /query and get typed columns and rows back.
GET /version returns the embedded DuckDB version and GET /health is the unauthenticated health check.
The PostgreSQL wire protocol is not offered: the shim does not implement it yet, so the catalogue lists only the HTTPS port.
| Status | Available |
|---|---|
| Category | Analytics (embedded) |
| Versions | 1.5 (newest is the default) |
| Protocol and port | HTTPS on 443 |
| Runtime | Single-node engine (ghcr.io/zerobase/duckdb-server) |
| Backups | CHECKPOINT + file copy |
| Point-in-time recovery | No |
| Pause | Scale to zero |
| Free plan | Yes (size f0) |
| Licence | MIT |
When to use it
Section titled “When to use it”- Shared analytical work on one dataset: internal dashboards, notebooks and scheduled reports.
- Ad-hoc SQL over event or export data that you load once and query many times.
- Prototyping analytics before you need a distributed column store.
Pick ClickHouse when many users or services query at once, when data arrives continuously at high rates, or when the dataset outgrows one node. Pick PostgreSQL for transactional application data.
Create an instance
Section titled “Create an instance”- Open the portal and choose New instance.
- Pick DuckDB and a version (1.5).
- Choose a size and region. On the Free plan the size is f0. Secure placement is listed only after your organization has signed the BAA.
- Check the hourly price and monthly estimate, then confirm. The Connect tab fills in when the instance is ready.
zb instances create --engine duckdb --engine-version 1.5 \ --size s1 --region us-east --name duckdb-demo --wait# On the Free plan, use --size f0
# Reveal the credentials once and store them in your secret managerzb instances credentials reveal duckdb-democurl -sS https://api.databasezy.com/v1/orgs/$ZB_ORG/projects/$ZB_PROJECT/instances \ -H "Authorization: Bearer $ZB_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "engine": "duckdb", "engine_version": "1.5", "size": "s1", "region": "us-east", "name": "duckdb-demo"}'
The response is 201 with the instance in status requested, or 202 when a
team approval policy applies. See the REST API reference.
Connect
Section titled “Connect”Endpoint and credentials
Section titled “Endpoint and credentials”| Host | duckdb-<id>.<region>.databasezy.com, for example duckdb-7f3k.us-east.databasezy.com |
|---|---|
Port 443 | HTTP API, POST /query |
| Single-IP regions |
Single-IP regions use 8443 for HTTP engines instead of 443. The
portal Connect page always shows the right port.
|
| TLS | Required on every port; plaintext is refused. Verify the server: https:// (or the driver's TLS flag) with normal certificate verification; the certificate is publicly trusted. |
| Credentials | Username app and a generated password, presented as HTTP Basic authentication. Shown once at creation; reveal or rotate it from the Connect tab. |
Every endpoint except /health needs HTTP Basic authentication with the generated user and password. Requests are JSON:
{"sql": "...", "params": [...]}, where params is optional and binds to ? or $1 placeholders.
Drivers and clients
Section titled “Drivers and clients”DuckDB listens on port 443 (HTTP API, POST /query). Versions: 1.5. Replace the example host with the one on your instance's Connect tab; credentials are shown once at creation.
https://duckdb-7f3k.us-east.databasezy.com:443import osimport requests
r = requests.post( "https://duckdb-7f3k.us-east.databasezy.com:443/query", auth=("app", os.environ["ZB_PASSWORD"]), # HTTP Basic over TLS json={"sql": "select ? + 1 as answer", "params": [41]}, timeout=60,)r.raise_for_status()body = r.json()print(body["columns"], body["rows"], body["truncated"])Tested with: DuckDB 1.5 · requests 2.32
const auth = "Basic " + Buffer.from(`app:${process.env.ZB_PASSWORD}`).toString("base64");
const res = await fetch("https://duckdb-7f3k.us-east.databasezy.com:443/query", { method: "POST", headers: { Authorization: auth, "Content-Type": "application/json" }, body: JSON.stringify({ sql: "select count(*) as n from read_parquet($1)", params: ["events.parquet"] }),});if (!res.ok) throw new Error((await res.json()).error);console.log(await res.json());Tested with: DuckDB 1.5 · Node 22 fetch
# HTTP Basic auth with the generated user and passwordcurl -sS https://duckdb-7f3k.us-east.databasezy.com:443/query -u app:$ZB_PASSWORD \ -H "Content-Type: application/json" \ -d '{"sql": "select 42 as answer"}'
curl -sS https://duckdb-7f3k.us-east.databasezy.com:443/version -u app:$ZB_PASSWORDTested with: DuckDB 1.5 · curl 8
A query that returns rows responds with columns, rows, row_count, truncated and elapsed_ms. Statements without
results return empty columns and rows with row_count set to the number of rows changed. Errors return a non-2xx
status with {"error": "..."}: 400 for SQL errors, 401 for missing or wrong credentials, 413 for a body over
1 MiB.
Values map to JSON predictably: DECIMAL and out-of-range HUGEINT become strings, timestamps become ISO-like
strings, BLOB becomes base64, and LIST, STRUCT and MAP become JSON arrays and objects.
See Connecting to Databasezy for the CA bundle, the IP allow-list and credential rotation, which work the same for every engine.
Migrate in
Section titled “Migrate in”| Source | How | Continuous sync | Guide status |
|---|---|---|---|
| Local files and dumps | File upload, Local tools (zb migrate --from local) | No | Available |
| Another Databasezy instance | Instance to instance | No | Coming soon · phase 2 |
External sources are not supported yet; copies between Databasezy DuckDB instances are. To load data, send CREATE TABLE
and batched INSERT statements through the API (each request body is limited to 1 MiB), or export from your source as
SQL inserts.
How migrations work explains preflight, verification and cutover, and engine conversions covers moves between compatible engines.
Backups and restore
Section titled “Backups and restore”A backup runs CHECKPOINT, which folds the write-ahead log into the database file, and then copies the data directory
to object storage. The server also checkpoints when it shuts down, so a paused or restarted instance leaves a
consistent file.
DuckDB backups use CHECKPOINT + file copy. They run inside the instance's namespace, stream straight to the cell's object storage and are checksummed on upload. How often they run and how long they are kept follows your plan's backup policy. A backup is always taken before a resize or a version upgrade.
Point-in-time recovery is not available for DuckDB. A restore returns the data as of a scheduled or manual backup. Restores create a new instance by default and leave the original untouched; an in-place restore asks you to type the instance name and takes a pre-change backup first.
zb backups create duckdb-demo --label before-release # manual snapshotzb backups list duckdb-demozb backups restore duckdb-demo <backup-id> --name duckdb-demo-restorePause and scale to zero
Section titled “Pause and scale to zero”DuckDB can scale to zero. A paused instance has no running pods and bills no compute; its storage and backups are kept and billed as usual. Connections are refused until you resume it. On the Free plan an instance pauses by itself after 15 minutes without connections and wakes on the next one; the gateway holds that connection for up to 30 seconds while it starts.
zb instances pause duckdb-demozb instances resume duckdb-demoSee Pause and resume for schedules, wake times and billing while paused.
Limits, versions and lifecycle
Section titled “Limits, versions and lifecycle”Versions and lifecycle
Section titled “Versions and lifecycle”- Supported versions:
1.5. New instances default to1.5, the only version offered. - Minor and patch releases are applied for you in the maintenance window, always after a pre-change backup.
- New majors are added within 60 days of the upstream release. A major reaches end of life on Databasezy six months after upstream ends support, with notices 90, 30 and 7 days ahead.
Sizes and limits
Section titled “Sizes and limits”DuckDB runs on every size, including the Free plan's f0. The size sets the CPU, memory, storage ceiling and connection limit; the gateway refuses connections over the limit with a protocol error. Storage grows in steps up to the ceiling, and you can resize at any time.
| Size | vCPU | Memory | Max storage | Max connections | ≈ $ / month |
|---|---|---|---|---|---|
f0 | 0.063 | 512 MiB | 1 GB | 20 | Free |
s0 | 0.25 | 1 GiB | 20 GB | 60 | $10 |
s1 | 0.5 | 2 GiB | 50 GB | 100 | $15 |
s2 | 1 | 4 GiB | 200 GB | 200 | $60 |
m2 | 2 | 8 GiB | 500 GB | 400 | $110 |
m4 | 4 | 16 GiB | 1 TB | 800 | $210 |
l8 | 8 | 32 GiB | 4 TB | 1,500 | $410 |
l16 | 16 | 64 GiB | 8 TB | 3,000 | $960 |
xl32 | 32 | 128 GiB | 16 TB | 5,000 | $1,870 |
Full details, including hourly prices and burst CPU, are in the size catalogue; plan quotas are in limits and quotas.
The HTTP server has limits of its own that matter more than the size table:
- One query at a time. All requests share one DuckDB connection and run in order. Transaction state is shared too,
so treat every request as autocommit and do not send
BEGINandCOMMITin separate requests. - 10,000 rows per response. Larger results come back with
truncated: true. Aggregate in SQL, or page withLIMITandOFFSET. - 1 MiB request bodies. Split large inserts into batches.
- No per-query timeout or cancellation. A long query holds the connection until it finishes.
Licence
Section titled “Licence”Databasezy runs DuckDB under the MIT licence, as listed in the engine catalogue. Your data and schemas are yours whatever the server's licence; the licence governs the server software we run.
DuckDB and the zb-duckdb-server shim are both MIT-licensed open source.
Security
Section titled “Security”- TLS on every connection. TLS 1.2 is the minimum and TLS 1.3 is preferred; plaintext is never
offered. Verify the server, not just the encryption: use
HTTPS with certificate verification. See TLS and the CA bundle. - IP allow-list. The gateway checks the client address before authentication, on every plan.
Manage it under Network → Allow-list in the portal or with
PUT /v1/orgs/{org}/instances/{id}/network. - Credentials. Generated inside the cell, shown once, never stored by the control plane. Rotate them with an overlap window so nothing breaks.
- Secure hosting. Secure placement (HIPAA-ready) is a per-instance option once your organization has signed the BAA: dedicated nodes, customer-managed keys and immutable backups. See Secure hosting and the BAA.
- Staff access. Databasezy staff cannot read your data without a grant you issue. See data confidentiality.
Can I connect with a PostgreSQL client?
Section titled “Can I connect with a PostgreSQL client?”Not yet. The PostgreSQL wire listener is planned for the DuckDB shim but is not implemented, so only the HTTPS API is offered.
How many queries can run at once?
Section titled “How many queries can run at once?”One. Queries share one connection and run in order. DuckDB on Databasezy suits a team’s analysis, not a high-concurrency application backend.
Is DuckDB on the Free plan?
Section titled “Is DuckDB on the Free plan?”Yes, on the f0 size.