QuestDB Python Client
The `questdb` library is the official Python client for QuestDB, a high-performance open-source SQL database for time-series and analytics. It provides efficient ingestion of data via InfluxDB Line Protocol (ILP) over TCP or HTTP, supporting various Python data types, Pandas DataFrames, and NumPy arrays. The current version is 4.1.0, and releases are typically feature-driven, often aligning with new QuestDB server capabilities.
Common errors
-
questdb.client.IngressError: Ingress error: status code 400. Bad Request: table 'my_table' does not exist
cause The QuestDB server rejected the data due to a schema mismatch or the target table/column not existing, or other data validation issues. This error typically occurs when using ILP over HTTP (v2.0.0+).fixCheck QuestDB server logs for detailed error messages. Ensure the table and columns exist, and the data types sent match the table schema. If auto-creation is expected, verify server configuration. -
ConnectionRefusedError: [Errno 111] Connection refused
cause The Python client could not establish a connection to the QuestDB server at the specified address and port. This usually means the server is not running, is configured on a different port, or a firewall is blocking the connection.fixVerify that the QuestDB server is running. Check the server's ILP port (default 9000 for HTTP, 8812 for TCP) and host in its configuration. Ensure no firewall is blocking access. -
TypeError: object of type Decimal is not JSON serializable
cause You are attempting to send a `decimal.Decimal` object to QuestDB using an older client version (<4.1.0) or an older QuestDB server (<9.2.0) that does not natively support the `DECIMAL` type.fixUpgrade the `questdb` client to 4.1.0 or newer AND ensure your QuestDB server is 9.2.0 or newer to use the native `DECIMAL` type. Alternatively, convert `decimal.Decimal` objects to `float` or `str` before sending (with potential precision loss). -
RuntimeError: unsupported array type for column 'my_array_col'
cause You are attempting to send a NumPy array that is not of `np.float64` dtype, or you are using an older client version (<3.0.0), or an older QuestDB server (<9.0.0) that does not support n-dimensional arrays.fixEnsure your NumPy array has `dtype=np.float64`. Upgrade the `questdb` client to 3.0.0 or newer and ensure your QuestDB server is 9.0.0 or newer to enable n-dimensional array ingestion.
Warnings
- breaking Version 4.0.0 introduced support for nanosecond precision timestamps via the `.row()` API. While it enhances precision, users relying on older QuestDB servers (pre-9.1.0) might encounter issues or loss of precision if sending nanoseconds to `TIMESTAMP` columns, which only support microsecond precision. For full nanosecond support, QuestDB 9.1.0+ is required with `TIMESTAMP_NS` columns.
- breaking Version 3.0.0 introduced support for n-dimensional NumPy arrays and a new protocol version (2) for this feature. This requires QuestDB server 9.0.0 or higher. Attempting to send array data to older QuestDB servers will not work.
- breaking Version 2.0.0 was a major release introducing ILP over HTTP, which became the preferred method for sending data due to better error feedback. If migrating from v1.x (TCP-only), connection configurations (`Sender.from_conf()`) and error handling (e.g., `IngressError`) will need to be updated.
- gotcha Version 4.1.0 added support for `decimal.Decimal` objects. This feature requires QuestDB server 9.2.0 or newer to correctly handle the native `DECIMAL(precision, scale)` column type. Sending decimals to older server versions will likely result in type errors or incorrect ingestion.
- gotcha In versions 2.0.0 and 2.0.1, the `auto_flush_rows` default for HTTPS connections was incorrectly set to a low value (600 rows), leading to suboptimal performance due to frequent flushes. This was fixed in v2.0.2.
Install
-
pip install questdb
Imports
- Sender
from questdb.client import Sender
Quickstart
import os
import time
from questdb.client import Sender
from datetime import datetime, timezone
# Configure QuestDB connection (ILP over HTTP)
# Use os.environ.get for security and flexibility in deployment
QDB_HOST = os.environ.get("QDB_HOST", "localhost")
QDB_PORT = os.environ.get("QDB_PORT", "9000")
QDB_AUTH = os.environ.get("QDB_AUTH", "") # Format: "username:token"
conf = f'http::addr={QDB_HOST}:{QDB_PORT};'
if QDB_AUTH:
conf += f'auth={QDB_AUTH};' # Assumes auth syntax for QuestDB 7.0+
else:
print("Warning: QDB_AUTH environment variable not set. Connecting without authentication.")
try:
with Sender.from_conf(conf) as sender:
# Ingest a single row of data
sender.row(
"sensor_data",
columns={
"location": "london",
"temperature": 15.5,
"humidity": 70,
"event_time": datetime.now(timezone.utc)
},
at=datetime.now(timezone.utc) # QuestDB timestamp column
)
# Ingest another row, demonstrating nanosecond precision (client v4.0.0+)
# Note: Requires QuestDB server 9.1.0+ for nanosecond TIMESTAMP_NS type
nanos_timestamp = int(time.time_ns()) # Current time in nanoseconds
sender.row(
"sensor_data",
columns={
"location": "paris",
"temperature": 18.2,
"humidity": 65,
"event_time": datetime.now(timezone.utc)
},
at=nanos_timestamp # This sends nanosecond precision
)
sender.flush() # Ensure all buffered data is sent
print("Data sent successfully to QuestDB!")
except Exception as e:
print(f"Failed to send data: {e}")
print(f"Please ensure QuestDB server is running and accessible at http://{QDB_HOST}:{QDB_PORT}")