on GitHub

Attach from DuckDB

An n6k server publishes one or more catalogs. A DuckDB client attaches a catalog by name and from then on treats it as an ordinary database: SHOW ALL TABLES, SELECT, JOIN, INSERT. Nothing about the query has to know the table is remote.

Every example on this page runs against the demo server this site hosts, and the output shown is what it returns.

Install and load

The extension is unsigned, so the CLI has to be started with -unsigned:

-- launch the CLI as:  duckdb -unsigned
INSTALL n6k FROM 'https://storage.googleapis.com/n6k-duckdb-release';
LOAD n6k;

Attach

CREATE SECRET n6kdemo (
  TYPE n6k,
  TOKEN 'demo-token',
  SCOPE 'n6kd-demo-106595059298.us-central1.run.app'
);

ATTACH 'n6ks://n6kd-demo-106595059298.us-central1.run.app' AS demo (TYPE n6k);

TYPE n6k is required — DuckDB does not infer the storage type from the URL scheme. n6k:// is plaintext, n6ks:// is TLS; the alias after AS is the name the catalog gets locally and the catalog requested from the server.

Omitting the port

With no port, the scheme's default applies — 443 for n6ks://, 80 for n6k://. A server on any other port needs it spelled out, which for a local one is the common case: n6k://localhost:8080.

Read

The catalog behaves like any other:

SHOW ALL TABLES;
databaseschemanamecolumn_namescolumn_types
demomainaudit_log[id, occurred_at, actor, action][INTEGER, TIMESTAMP, VARCHAR, VARCHAR]
demomaincustomers[id, name, region, signed_up][INTEGER, VARCHAR, VARCHAR, DATE]
demomainorders[id, customer_id, placed_at, amount, status][INTEGER, INTEGER, DATE, DECIMAL(10,2), VARCHAR]

Types survive the wire — DECIMAL(10,2) arrives as DECIMAL(10,2), not as a float. A join across two remote tables is one query:

SELECT c.region, count(*) AS orders, sum(o.amount) AS revenue
FROM demo.orders o
JOIN demo.customers c ON c.id = o.customer_id
GROUP BY 1 ORDER BY 3 DESC;
regionordersrevenue
APAC5000023009000.00
LATAM5000023003100.00
NA5000022996300.00
EMEA5000022989500.00

That scanned 200,000 rows. Only the columns the query names are fetched, and =, !=, <, <=, >, >=, IN, IS NULL and IS NOT NULL predicates are pushed to the server rather than filtered after transfer — so narrowing the query narrows the traffic.

Join a remote table to a local file

This is the part that has no equivalent in a REST API. The attached catalog and your own local data live in the same FROM clause:

SELECT r.rep, count(*) AS orders, sum(o.amount) AS revenue
FROM demo.orders o
JOIN demo.customers c ON c.id = o.customer_id
JOIN 'reps.parquet' r ON r.region = c.region   -- a file on your laptop
GROUP BY 1 ORDER BY 3 DESC;
repordersrevenue
Lin5000023009000.00
Sofia5000023003100.00
Ada5000022996300.00
Grace5000022989500.00

The server never sees reps.parquet, and your laptop never downloads demo.orders. DuckDB plans across both, pushes what it can to each side, and joins the results locally.

Write

Tables the server marks writable accept ordinary DML:

UPDATE demo.orders SET status = 'refunded' WHERE id = 42;
SELECT id, status FROM demo.orders WHERE id = 42;
idstatus
42refunded

The write lands on the server, not in a local copy — detach, reattach from a different machine, and it is still there. INSERT, DELETE, CREATE TABLE AS and views work the same way.

Run SQL on the server

Sometimes you want the server to evaluate the statement rather than the client. Each attached catalog exposes:

FunctionWhat it does
demo.query(sql)Run a SELECT on the server, stream the result back
demo.exec(sql)Run a statement for its effect
demo.func(args)Call an RPC the server registered

When it does not work

What you didWhat comes back
Attached with no token, to a server that requires oneInvalid Error: InvalidInputException: unauthorized
Wrote to a table the server marks readBinder Error: Table 'audit_log' is read-only
n6k:// against a TLS-only hostFailed reading HTTP status line from ws://… — use n6ks://
Reached for the server's filesystemPermission Error: … file system operations are disabled by configuration

The last two rows are the server's policy, not the client's: see permissions.