Airport icon

Airport

ATTACH an Arrow Flight server as a DuckDB catalog and query it in SQL. Best fit: custom Flight services you build in Python / Go / Java, plus Flight-native systems like Dremio and InfluxDB 3. Capabilities (pushdown, mutation, schema discovery) follow what your Flight server implements.

Install

-- Install the extension
INSTALL airport FROM community;

-- Load it into your session
LOAD airport;

-- Attach a remote Arrow Flight database. `scope` matches the secret
-- to the URL you ATTACH against.
CREATE SECRET my_flight (
  TYPE airport,
  scope 'grpc+tls://flight.example.com:8815',
  auth_token 'your-token'
);

ATTACH 'grpc+tls://flight.example.com:8815' AS remote (TYPE airport);

-- Query as if it were local
SELECT * FROM remote.public.events LIMIT 100;

-- Inspect available flights from a server
SELECT * FROM airport_flights('grpc+tls://flight.example.com:8815');

Deep Dive

Technical Details

Airport — Arrow Flight for DuckDB

What Airport gets you

If you operate a service that already speaks Arrow Flight — a custom Python or Go data API, an internal federation gateway, or a Flight-native system like Dremio or InfluxDB 3 — Airport makes it queryable from DuckDB with a single ATTACH:

CREATE OR REPLACE SECRET my_service (
  TYPE airport,
  scope 'grpc+tls://flight.example.com:8815',
  auth_token :token
);

ATTACH 'grpc+tls://flight.example.com:8815' AS svc (TYPE airport);

SELECT user_id, COUNT(*) AS events
FROM svc.public.activity
WHERE ts >= CURRENT_DATE - 7
GROUP BY user_id;

No client library, no DataFrame round-trip, no separate query API on top of your service. Just SQL.

Airport is a Flight client — its capabilities follow your server's

Airport translates DuckDB SQL into Arrow Flight RPC calls. Anything the protocol can express, Airport can carry; anything beyond what your Flight server implements doesn’t suddenly start working because Airport is loaded.

  • Filter pushdown runs to the extent your server honors GetFlightInfo filter predicates. Servers that don’t push filters down will see DuckDB scan the whole result and filter locally.
  • Mutation (INSERT / UPDATE / DELETE) requires the server to implement DoPut for those operations. Read-only servers stay read-only.
  • Schema discovery depends on the server exposing a ListFlights / catalog interface. Servers that only answer specific descriptors won’t ATTACH cleanly — use airport_take_flight for one-off reads instead.

What can I connect to?

The honest answer: any service that implements Arrow Flight. In practice that’s a narrower list than “data systems that use Arrow internally.”

Confirmed Flight-speaking systems:

Not Arrow Flight, even if they use Arrow internally:

Snowflake, Microsoft Fabric, BigQuery, and several other warehouses use Arrow as their result-format wire encoding but don’t expose a public Flight server you can ATTACH to. Airport won’t help you here. For database-style remote query against systems with ADBC drivers, see the sibling adbc_scanner extension.

Who Airport is for

The most underrated angle: platform and data engineering teams who already run an internal data service. If your service produces tabular data and you’re considering inventing a SQL query API on top of it (translating predicates, paginating, handling joins), don’t. Implement pyarrow.flight.FlightServerBase — a few dozen lines — and your service inherits SQL access for free via Airport. DuckDB becomes the query engine; you just write the data-fetch path.

The other natural fit is federation: DuckDB joining across multiple Flight backends (your custom service, a Dremio instance, an InfluxDB measurement) in one query, without an orchestration layer.

How it integrates with DuckDB

Airport vs ADBC Scanner

Both extensions stream Arrow from a remote system end-to-end, but they target different worlds — pick by what’s on the other end of the wire:

  • Use Airport when the upstream speaks Arrow Flight — typically custom services, Flight-native systems, or federation gateways. Flight is an RPC protocol.
  • Use adbc_scanner when the upstream is a database with an ADBC driver — SQLite, PostgreSQL, Snowflake, BigQuery, etc. ADBC is a client API standard, not a wire protocol.
  • Both can coexist in the same DuckDB session: Airport for Flight-native services, adbc_scanner for traditional databases, all queryable side by side.

Background: what is Arrow Flight?

Arrow Flight is the Apache Arrow project’s wire protocol for moving Arrow data over the network. It runs on gRPC over HTTP/2 and uses Arrow’s columnar IPC format end-to-end, so result batches arrive on the client in the same layout the server produced them — no row/column transposition. The protocol’s standard verb vocabulary — ListFlights, GetFlightInfo, DoGet, DoPut, DoExchange, DoAction — is what Airport translates DuckDB SQL into. The full design rationale for Airport and server implementation guides live at airport.query.farm.

Reference

Extension Contents

Quick reference to all available functions and settings organized by category.

Name Description
Arrow Flight Catalog
airport Attach an Arrow Flight server as a DuckDB catalog
Arrow Flight Connection
airport Connection details for an Arrow Flight server
Diagnostics

Identify the Airport extension version and the User-Agent it advertises to remote servers. Useful for debugging connectivity issues and matching server logs to a specific extension build.

airport_user_agent() Returns the User-Agent header string Airport sends with Arrow Flight requests
airport_version() Returns the version string of the loaded Airport extension
Discovery

Enumerate what an Arrow Flight server exposes — its databases, its flights (each with a schema and metadata). Use these before ATTACH to figure out what's available.

airport_databases() Lists databases exposed by the Arrow Flight server identified by the given secret
airport_flights() Lists the flight descriptors offered by an Arrow Flight server, with their schemas and metadata
Operations

Execute work against an Arrow Flight server. Stream the result of a specific ticket inline (airport_take_flight) or invoke a server-defined Action for non-query operations (airport_action).

airport_action() Invokes a custom Flight Action on the server (the Arrow Flight RPC for non-query operations)
airport_take_flight() Fetches the result of a specific Arrow Flight ticket as a DuckDB table

API Reference

Function Documentation

Detailed documentation for each function including signatures, parameters, and examples.

airport_action

Table Function Operations
Signature
airport_action(col0: VARCHAR, col1: VARCHAR, headers := MAP(VARCHAR, VARCHAR), secret := VARCHAR, auth_token := VARCHAR) → None
Parameters
Parameter Type Mode Description
col0 VARCHAR Positional
col1 VARCHAR Positional
headers MAP(VARCHAR, VARCHAR) Named
secret VARCHAR Named
auth_token VARCHAR Named
Returns
Description

Invokes a custom Flight Action on the server (the Arrow Flight RPC for non-query operations). Used for server-defined commands like refresh, snapshot, or stored-procedure calls.

Examples

airport_databases

Scalar Function Discovery
Signature
airport_databases(server_location: ANY) → None
Parameters (Positional)
Parameter Type Mode Description
server_location ANY Positional
Returns
Description

Lists databases exposed by the Arrow Flight server identified by the given secret. Used to enumerate what's available before attaching.

Examples

airport_flights

Table Function Discovery
Signature
airport_flights(col0: VARCHAR, secret := VARCHAR, auth_token := VARCHAR) → None
Parameters
Parameter Type Mode Description
col0 VARCHAR Positional
secret VARCHAR Named
auth_token VARCHAR Named
Returns
Description

Lists the flight descriptors offered by an Arrow Flight server, with their schemas and metadata. The starting point for ad-hoc querying without ATTACH.

Examples

airport_take_flight

Table Function Operations
Signature
airport_take_flight(col0: POINTER, col1: POINTER, col2: VARCHAR, at_value := ANY, at_unit := VARCHAR, secret := VARCHAR, auth_token := VARCHAR) → None
Parameters
Parameter Type Mode Description
col0 POINTER Positional
col1 POINTER Positional
col2 VARCHAR Positional
at_value ANY Named
at_unit VARCHAR Named
secret VARCHAR Named
auth_token VARCHAR Named
Returns
Description

Fetches the result of a specific Arrow Flight ticket as a DuckDB table. Use when you have a known flight descriptor and want to stream its results inline.

Examples

airport_user_agent

Scalar Function Diagnostics
Signature
airport_user_agent() → VARCHAR
Parameters
Parameter Type Mode Description
Returns
Description

Returns the User-Agent header string Airport sends with Arrow Flight requests.

Examples

airport_version

Scalar Function Diagnostics
Signature
airport_version() → VARCHAR
Parameters
Parameter Type Mode Description
Returns
Description

Returns the version string of the loaded Airport extension.

Examples

Database Storage

Storage Extensions

Storage extensions that enable secure database attachments with encryption, secret management, and credential rotation.

airport

Description

Attach an Arrow Flight server as a DuckDB catalog. Once attached, schemas, tables, and SQL operations on the remote server become accessible like any local database — joins, filters, aggregates, and (when the server supports the corresponding Flight RPCs) `INSERT` / `UPDATE` / `DELETE`. Pass the Flight URL as the database identifier; the matching `airport` secret (if any) is picked up automatically by URL scope. The optional `location` ATTACH parameter overrides the URL when you want a logical name as the database identifier.

Parameters
Parameter Type Required Description
location VARCHAR Optional Optional Arrow Flight server URI override (e.g. `grpc://host:8815` or `grpc+tls://host:8815`). When omitted, the URL passed as the database identifier in `ATTACH '<url>' AS <alias>` is used.
auth_token VARCHAR Optional Bearer token sent in the gRPC Authorization header. Recommended via [`CREATE SECRET`](#secrets) rather than inline so it's not stored in query text.
Examples
1

Attach by URL with credentials picked up from a matching secret (recommended)

-- 1. Stash credentials once. `scope` is the URL prefix the secret applies to.
CREATE SECRET my_flight (
  TYPE airport,
  scope 'grpc+tls://flight.example.com:8815',
  auth_token :token
);

-- 2. Attach the URL — the Secrets Manager picks up `my_flight`
--    automatically because the URL matches its scope.
ATTACH 'grpc+tls://flight.example.com:8815' AS remote (TYPE airport);

-- 3. Query as if it were local
SELECT user_id, COUNT(*) AS events
FROM remote.public.activity
WHERE ts >= CURRENT_DATE - 7
GROUP BY user_id;
2

Attach inline without a secret (good for ad-hoc connections to unauthenticated servers)

ATTACH 'grpc://localhost:8815' AS remote (TYPE airport);

SHOW TABLES FROM remote.public;
3

Mutate a remote table — works only when the Flight server implements `DoPut` for the operation

ATTACH 'grpc+tls://flight.example.com:8815' AS remote (TYPE airport);

INSERT INTO remote.public.events
SELECT user_id, event_type, ts
FROM staging.new_events;

UPDATE remote.public.profile
  SET country = 'CA'
  WHERE user_id = 12345;

Security

Secrets

DuckDB secrets for securely storing credentials and encryption keys used by the airport extension.

airport

Description

Connection details for an Arrow Flight server. Used by `ATTACH` to establish a database connection and by the discovery / operations functions when invoked with a secret reference. `scope` is the Flight URL the secret applies to (DuckDB Secrets Manager scope-matches against it).

Parameters
Parameter Type Required Description
scope VARCHAR Required Arrow Flight server URI, e.g. `grpc://host:8815` or `grpc+tls://host:8815`. The DuckDB Secrets Manager matches `ATTACH` / function calls to a secret by URL prefix against this value.
auth_token VARCHAR Optional Bearer token sent in the gRPC Authorization header.
Examples
1

Create a secret for a TLS-protected Flight server

CREATE SECRET my_flight (
  TYPE airport,
  scope 'grpc+tls://flight.example.com:8815',
  auth_token 'your-token'
);
2

Attach the database — the matching secret is picked up automatically by URL scope

ATTACH 'grpc+tls://flight.example.com:8815' AS remote (TYPE airport);
SELECT * FROM remote.public.events LIMIT 10;

Practical Examples

Cookbook

Real-world recipes and patterns for common use cases.

Try it against the live demo server

Query.Farm runs a public demo Flight server at grpc+tls://hello-airport.query.farm so you can exercise Airport without building anything. Attach it, switch to the static schema, and join across two of its tables:

-- Connect to a remote Arrow Flight server
ATTACH 'hello' (TYPE AIRPORT, location 'grpc+tls://hello-airport.query.farm');

-- Switch to the static schema
USE hello.static;

-- Query remote tables with standard SQL — notice the join across two remote tables
SELECT greeting || ', ' || first_name || ' welcome to Airport.' AS greeting
FROM greetings
JOIN people ON people.language = greetings.language
LIMIT 3;

The chat schema demonstrates writes against a Flight server too — auto-assigned identity, message inserts, and a recent-messages query in the same session:

-- Switch to the chat schema
USE hello.chat;

-- Get your auto-generated identity
SELECT * FROM identity;

-- Post a message to the 'airport' channel
INSERT INTO messages (channel, message)
VALUES ('airport', 'Hello from Airport!');

-- See all recent messages
SELECT sender, message, timestamp
FROM messages
WHERE channel = 'airport'
ORDER BY timestamp DESC
LIMIT 10;

See airport.query.farm for the demo’s full schema reference and notes on the underlying Flight server implementation.

Attach a Flight Database

The most powerful way to use Airport: attach an Arrow Flight server as a DuckDB database via ATTACH and query it like any other catalog.

-- 1. Store credentials with CREATE SECRET. `scope` is the Flight URL
--    the secret applies to — DuckDB matches the secret by URL prefix.
CREATE OR REPLACE SECRET my_flight (
  TYPE airport,
  scope 'grpc+tls://flight.example.com:8815',
  auth_token 'your-bearer-token'
);

-- 2. ATTACH the URL directly. The Secrets Manager picks up `my_flight`
--    automatically because the URL matches its scope.
ATTACH 'grpc+tls://flight.example.com:8815' AS remote (TYPE airport);

-- 3. Query as if it's local — joins, filters, aggregates all push down
--    to the Flight server when supported.
SELECT user_id, COUNT(*) AS events
FROM remote.public.activity
WHERE ts >= CURRENT_DATE - 7
GROUP BY user_id
ORDER BY events DESC
LIMIT 50;

DuckDB’s full SQL surface works against remote tables — joins across local and remote catalogs, CTEs, window functions, materialized CTAS into local tables. Credentials live in the DuckDB Secrets Manager (see CREATE SECRET) so they’re never inlined into queries — the secret is matched against the ATTACH URL by its scope prefix.

Discover What a Server Offers

Before attaching, list the databases and flights a server exposes:

-- Show databases the server hosts. `airport_databases` takes the
-- Flight URL — the same URL you'd pass to ATTACH.
SELECT * FROM airport_databases('grpc+tls://flight.example.com:8815');

-- Show all flights (schemas + metadata) under a server URL
SELECT * FROM airport_flights('grpc+tls://flight.example.com:8815');

-- Filter by descriptor pattern
SELECT * FROM airport_flights(
  'grpc+tls://flight.example.com:8815',
  /* criteria = */ 'tenant=acme'
);

The result is a table — pipe it into WHERE / LIMIT / joins to drill down without attaching. See airport_databases and airport_flights for the full signatures.

Stream a Specific Flight Inline

When you already have a flight descriptor and just want its rows once, skip ATTACH and call airport_take_flight directly:

SELECT *
FROM airport_take_flight(
  'grpc+tls://flight.example.com:8815',
  /* descriptor = */ '{"path":["sales","2026-04"]}'
)
LIMIT 100;

Useful for read-once jobs, exports, or wiring Flight responses into a CTAS.

Invoke a Server Action

Arrow Flight has a separate RPC channel called Actions for non-query operations — refreshing a materialized view, taking a snapshot, calling a stored procedure. Airport exposes them via airport_action:

-- Trigger a server-defined "refresh" action and capture the result body
SELECT *
FROM airport_action(
  'grpc+tls://flight.example.com:8815',
  /* action = */ 'refresh',
  /* body = */ '{"tenant":"acme","since":"2026-04-01"}'
);

The full set of available actions is server-defined — see your Flight server’s documentation for the action vocabulary.

Mutate a Remote Table

Airport supports INSERT / UPDATE / DELETE against attached Flight databases when the server implements the corresponding writer endpoints (Flight’s DoPut):

INSERT INTO remote.public.events
SELECT user_id, event_type, ts
FROM staging.new_events;

UPDATE remote.public.profile
SET country = 'CA'
WHERE user_id = 12345;

Whether each operation is supported depends on the server — airport_databases typically reports per-database write capabilities.

Diagnostics

SELECT airport_version();        -- e.g. '0.4.2'
SELECT airport_user_agent();     -- the User-Agent string Airport sends

Use airport_version and airport_user_agent to confirm what’s loaded and to match Flight server logs against a specific extension build when debugging.

Platform Support

Compatibility

Extension availability may vary by platform and DuckDB version. Check below to ensure this extension supports your environment before installation.

Quick Facts

Software License MIT
Pricing Free
Written In C++
Source Available Yes
View on GitHub
Usage
88,710+
loads in last 30 days

Platforms

Linux
Linux (musl)
macOS
Windows
WASM
Supported platform architectures
Linux: aarch64, x86_64
Linux (musl): x86_64
macOS: Intel, Apple Silicon
Windows: x86_64
WASM: Not available
Compiled binary sizes
Platform Architecture Size
Linux aarch64 22.63 MB
Linux x86_64 24.47 MB
Linux (musl) x86_64 25.33 MB
macOS Apple Silicon 15.61 MB
macOS Intel 16.78 MB
Windows x86_64 14.97 MB

Gzipped download size from the DuckDB community-extensions registry.

DuckDB Versions

Release calendar
Supported
v1.4.4 v1.5.2

SQL access to your Arrow Flight service

Install Airport, point it at a Flight server, and DuckDB queries it like any other catalog — to the extent the server supports the operations you need.