Query Firebolt from Python, R, Go and any other language with an ADBC driver manager. Results arrive as Apache Arrow, so they land straight in pyarrow, pandas or polars with no row-by-row conversion.
The driver is a single shared library loaded by your application; nothing is installed on the server.
| Connections | http:// and https:// (always certificate-verified) |
| Authentication | Firebolt SaaS: supported for engines v5 and later only, with a service account (docs/fb2-saas.md). Firebolt Core: authentication disabled, or a bearer token you already have (docs/authentication.md). |
| Platforms | Linux x86_64/aarch64 (glibc 2.28+), macOS arm64, Windows x86_64 |
| ADBC | The ADBC 1.0.0 API (see Feature & Type Support) |
This example runs Firebolt Core locally in Docker; to connect to Firebolt SaaS, see below. You need Docker and Python 3.9+. It takes about two minutes.
1. Install the driver manager and the driver (the driver via dbc):
pip install adbc-driver-manager pyarrow
dbc install firebolt --pre2. Start a local Firebolt engine
docker run -d --name firebolt -p 3473:3473 ghcr.io/firebolt-db/engine:5.0.0-pre.0.20260927210425.e91cd5bd17f8
until curl -fs http://localhost:3473/ping >/dev/null; do sleep 1; done; echo okIt starts with authentication disabled, so no credentials are needed.
3. Run a query
import adbc_driver_manager.dbapi as dbapi
with dbapi.connect(
driver="firebolt", db_kwargs={"uri": "http://localhost:3473"}
) as conn:
with conn.cursor() as cur:
cur.execute("SELECT 1 AS n, 'hello' AS greeting")
print(cur.fetch_arrow_table())pyarrow.Table
n: int32 not null
greeting: string not null
----
n: [[1]]
greeting: [["hello"]]
For engines v5 and later. Pass a service account and the account and engine
names instead of a uri; the driver finds the engine for you:
import os
import adbc_driver_manager.dbapi as dbapi
with dbapi.connect(
driver="firebolt",
db_kwargs={
"username": os.environ["FIREBOLT_CLIENT_ID"], # service account ID
"password": os.environ["FIREBOLT_CLIENT_SECRET"], # service account secret
"firebolt.account": "my_account",
"firebolt.engine": "my_engine",
"firebolt.database": "my_db",
},
) as conn:
with conn.cursor() as cur:
cur.execute("SELECT 1 AS n")
print(cur.fetch_arrow_table())Everything below works the same way. Options and details are in docs/fb2-saas.md.
Runnable versions of everything below are in examples/python/.
cur.execute("SELECT * FROM my_table")
table = cur.fetch_arrow_table() # pyarrow.Table
df = cur.fetch_df() # pandas.DataFrame
# Larger than memory? Stream it:
cur.execute("SELECT * FROM big_table")
for batch in cur.fetch_record_batch():
process(batch)Results are streamed, so a result you have not finished reading still occupies the connection. Other queries and commits on that connection fail until you read it to the end or close it (details).
adbc_ingest uploads a whole Arrow table in one request and can create the
target table for you, nested ARRAY and STRUCT columns included:
import pyarrow as pa
table = pa.table(
{
"id": pa.array([1, 2], pa.int32()),
"tags": pa.array([["a", "b"], ["c"]], pa.list_(pa.string())),
"meta": pa.array([{"k": 1}, {"k": 2}], pa.struct([("k", pa.int32())])),
}
)
with dbapi.connect(
driver="firebolt", db_kwargs={"uri": "http://localhost:3473"}, autocommit=True
) as conn:
with conn.cursor() as cur:
# mode: create, append, create_append or replace
cur.adbc_ingest("events", table, mode="replace")See Arrow to Database for the supported types.
Use Firebolt's positional placeholders $1, $2, … (not ? or %s). Values
are sent separately from the SQL, never spliced into it:
cur.execute("SELECT $1 + 1", (41,)) # → 42
cur.executemany("INSERT INTO events VALUES ($1, $2)", [(1, "a"), (2, "b")])Numbers, booleans, strings and None keep their type. Dates, timestamps and
decimals are sent as text — add a cast ($1::DATE) if Firebolt cannot infer one.
Named parameters use Firebolt's param() function and are always TEXT:
cur.execute("SELECT param('cutoff')::INT + 1", {"cutoff": 41})More in OPTIONS.md.
dbapi.connect() turns autocommit off by default (as PEP 249 requires), so your
statements run in a transaction until you commit:
cur.execute("INSERT INTO events VALUES (1, 'a')")
conn.commit() # or conn.rollback()Pass autocommit=True to dbapi.connect() to run each statement on its own.
conn.adbc_get_table_schema("events") # pyarrow.Schema
conn.adbc_get_objects(depth="columns") # catalogs → schemas → tables → columns
conn.adbc_get_table_types()
conn.adbc_get_info()Set these in db_kwargs:
| Key | Meaning |
|---|---|
uri |
Required. The engine endpoint, e.g. http://localhost:3473, or firebolt://host[:port]/[database], which uses TLS unless you add ?ssl_mode=disable (details) |
firebolt.database |
Database to use |
firebolt.token |
Bearer token; omit when authentication is disabled |
firebolt.timeout_sec |
How long to wait for the server, in seconds; 0 (default) means no limit (details) |
firebolt.ssl_certificate_path |
PEM CA bundle for https://, if not the system one |
firebolt.arrow_compression |
any (default) lets the server send compressed results; none turns that off; zstd or lz4 allows just that codec (details) |
Connection and statement options are in OPTIONS.md. These names will change when the driver adopts Firebolt's common SDK parameter names (mapping).
| Feature | Firebolt |
|---|---|
| Bulk Ingestion: Create | ✅ |
| Bulk Ingestion: Append | ✅ |
| Bulk Ingestion: Create/Append | ✅ |
| Bulk Ingestion: Replace | ✅ |
| Bulk Ingestion: Temporary Table | ❌ 1 |
| Bulk Ingestion: Target Catalog | ✅ 2 |
| Bulk Ingestion: Target Schema | ✅ |
| Non-nullable fields are marked NOT NULL | ✅ 3 |
| Catalog (GetObjects): depth=catalogs | ✅ |
| Catalog (GetObjects): depth=db_schemas | ✅ |
| Catalog (GetObjects): depth=tables | ✅ |
| Catalog (GetObjects): depth=columns (all) | ✅ |
| Get Parameter Schema | ✅ 4 |
| Get Table Schema | ✅ |
| Prepared Statements | ✅ 4 |
| Transactions | ✅ |
| Also | Firebolt |
|---|---|
| Streaming results as Arrow record batches | ✅ |
Query parameters ($1, named via param('name')) |
✅ 5 |
Session parameters (firebolt.session.*) |
✅ |
rowcount after DML |
❌ always -1 6 |
| Firebolt Core sign-in with credentials | ❌ see docs/authentication.md |
| Partitioned execution, Substrait | ❌ |
| ADBC 1.1.0-only functions | ❌ 7 |
| Database Type | Firebolt |
|---|---|
BOOLEAN |
bool |
INTEGER (INT) |
int32 |
BIGINT |
int64 |
REAL |
float |
DOUBLE PRECISION (FLOAT, DOUBLE) |
double |
TEXT (VARCHAR) |
string |
BYTEA |
binary |
DATE |
date32[day] |
TIMESTAMP (TIMESTAMPNTZ) |
timestamp[us] |
TIMESTAMPTZ |
timestamp[us, tz=UTC] |
NUMERIC(p, s) (DECIMAL(p, s)) |
decimal128(p, s) |
GEOGRAPHY |
binary 8 |
ARRAY(T) |
list<item: T> |
STRUCT(…) |
struct<…> |
ARRAY and STRUCT nest to any depth.
Ingest creates and loads tables from Arrow data; Bind sends values as query parameters.
| Arrow Type | Firebolt Type | Ingest | Bind |
|---|---|---|---|
bool |
BOOLEAN |
✅ | ✅ |
int8, int16, int32, uint8, uint16 |
INTEGER |
✅ | ✅ as BIGINT |
int64, uint32 |
BIGINT |
✅ | ✅ |
uint64 |
BIGINT |
||
float |
REAL |
✅ | ✅ as DOUBLE |
double |
DOUBLE PRECISION |
✅ | ✅ 10 |
string, large_string |
TEXT |
✅ | ✅ |
string_view |
TEXT |
❌ 11 | ✅ |
binary, large_binary, fixed_size_binary |
BYTEA |
✅ | ❌ 5 |
binary_view |
BYTEA |
❌ 11 | ❌ 5 |
date32[day], date64[ms] |
DATE |
✅ | ✅ as text 12 |
timestamp[s|ms|us|ns] |
TIMESTAMP |
✅ | ✅ as text 12 |
timestamp (with time zone) |
TIMESTAMPTZ |
✅ 13 | ✅ as text 12 |
time32, time64 |
(no mapping) | ❌ | ✅ as text 12 |
decimal128(p, s) |
NUMERIC(p, s) |
✅ 14 | ✅ as text 12 |
decimal32, decimal64, decimal256 |
NUMERIC(p, s) |
❌ 15 | ✅ as text 12 |
list<T>, large_list<T> |
ARRAY(T) |
✅ | ❌ 5 |
fixed_size_list<T> |
ARRAY(T) |
❌ 15 | ❌ 5 |
struct<…> |
STRUCT(…) |
✅ 3 | ❌ 5 |
dictionary<T> |
(value type) | ❌ 11 | ✅ decoded as T |
null |
(no mapping) | ❌ | ✅ as NULL |
map, duration, interval |
(no mapping) | ❌ | ❌ |
A NULL value binds as SQL NULL whatever its Arrow type.
- Firebolt has no temporary tables.
- Set a target schema too; a catalog alone is read as the schema.
- Only top-level columns become
NOT NULL; Firebolt requiresSTRUCTfields to be nullable. - Prepare is local;
adbc_prepare()asks the server for parameter types without running the query (details). - Binary and nested values cannot be bound as parameters; ingest them instead. Named parameters are always
TEXT(details). - Firebolt does not report affected rows; use
SELECT count(*). - Typed option setters,
Cancel,ExecuteSchema,GetStatistics,ErrorGetDetail.GetInfostill reports ADBC 1.1.0. - WKB bytes, without GeoArrow metadata.
- Values above the signed 64-bit maximum are rejected.
NaNand infinities are rejected.- Not supported by the Arrow IPC writer; cast to
string/binaryor decode the dictionary first. - Firebolt converts the text in most contexts; otherwise cast (
$1::DATE). - Stored as UTC; the original offset is not kept.
- Precision up to 38.
- Rejected by the server; cast to
decimal128orlist.
| Error | Fix |
|---|---|
Could not connect to server |
Is the engine running? Check curl -fsS http://localhost:3473/ping. |
Cluster not yet healthy |
The engine is still starting; retry in a few seconds. |
Database 'uri' must start with … |
Include the scheme: http://localhost:3473, not localhost:3473. |
HTTP 401 / 403 |
The engine requires authentication; see docs/authentication.md. |
No CA certificate bundle found / SSL peer certificate … was not OK |
Install your OS's ca-certificates, or set firebolt.ssl_certificate_path to your CA's PEM file. |
positional parameter $1, but it was not set |
Pass one value per $N placeholder; numbering starts at $1. |
current transaction is aborted |
A statement failed inside a transaction; call conn.rollback(). |
A query result stream is still open on this connection |
Read the previous result to the end or close it first, or use a second connection (details). |
Unknown Firebolt database option |
Check the option name against OPTIONS.md. |
Only needed to work on the driver itself; otherwise use a release. Requires git, Docker and Pixi:
git submodule update --init --recursive
pixi run make # → build/libadbc_driver_firebolt.{so,dylib,dll}Testing and contribution guidelines are in CONTRIBUTING.md.
| OPTIONS.md | Every option, error status and type mapping |
| docs/authentication.md | Authentication: what works now and what is planned |
| examples/python/ | Runnable examples |
| CONTRIBUTING.md | Building, testing and submitting changes |
| CHANGELOG.md | Release history |
FB2 only: engines (v5+) in a Firebolt 2.0 SaaS account — see docs/fb2-saas.md.
Apache 2.0 — see LICENSE.txt and NOTICE.txt. Release packages also include the licenses of all statically linked dependencies.