SQLRooms DuckDB websocket server runtime
Project description
SQLRooms Server
A Python-based server that runs a local DuckDB instance and supports queries over WebSockets, returning data in either Apache Arrow or JSON format. The server was originally developed for use with SQLRooms, but can be readily used as a generic DuckDB server in other contexts.
Note: This server was initially created as a fork of Mosaic DuckDB Server, with additional features and improvements.
Note: This package provides a local DuckDB server. To instead use SQLRooms with DuckDB-WASM in the browser, stick to the default
WasmDuckDbConnector.
Features
- WebSocket endpoint (WS-only)
- Arrow IPC results (binary framed) and JSON responses
- Concurrent query execution using a shared thread pool (per-task cursors)
- Per-query cancellation via
duckdb.interrupt(WebSockettype:"cancel") - WebSocket multiplexing with
queryIdcorrelation - Subscribe/notify over WebSocket using Socketify publish/subscribe
- Disk-backed result cache with per-key locking (prevents duplicate compute)
- One-time retry on transaction conflicts (e.g., concurrent UPDATE vs ALTER)
- Graceful shutdown (SIGINT/SIGTERM): cancel queries, FORCE CHECKPOINT, close, stop executor
- Optional bearer authentication for HTTP and WebSocket endpoints
- Optional sync (CRDT) over WebSocket (Loro), with snapshots stored either in the main DB or an attached DuckDB file
Installation and usage
We recommend running the server in an isolated environment with uvx. For example, to directly run the server, use:
uvx sqlrooms-server
Alternatively, you can install the server with pip install sqlrooms-server. Then you can start the server with sqlrooms-server --db-path /absolute/path/to/my.db --port 4000.
Compatibility:
sqlrooms-serveris provided as an alias console script for backward compatibility.
Command-line arguments
-
--db-path(optional): Path to DuckDB database file. Defaults to:memory:. -
--port(default:4000): Port to listen on. -
--extensions(optional): Comma-separated list of extensions to preload. Examples:httpfsspatialh3@community
-
--auth-token(optional): If provided, enables bearer authentication. WebSocket clients must first send{ "type": "auth", "token": "<TOKEN>" }. -
--sync(optional): Enables the optional sync (CRDT) module. When enabled, the server maintains per-room Loro CRDT docs, persists snapshots, and exposes CRDT WebSocket messages alongside the existing query protocol. -
--meta-namespace(default:__sqlrooms): Namespace where SQLRooms meta tables are stored (UI state + CRDT snapshots). If--meta-dbis provided, this is the ATTACH alias; otherwise it is a schema in the main DB. -
--meta-db(optional): If provided, attaches this DuckDB file under--meta-namespaceand stores meta tables there. If omitted, creates/uses the--meta-namespaceschema within the main DB.
Examples:
# In-memory DB with httpfs only (default)
uv run sqlrooms-server
# File-backed DB with multiple extensions
uv run sqlrooms-server --db-path /tmp/my.db --port 4000 --extensions httpfs,spatial,h3@community
# Enable sync using a schema within the main DB
uv run sqlrooms-server --db-path /tmp/my.db --sync
# Enable sync and store meta tables in a dedicated attached DuckDB file
uv run sqlrooms-server --db-path /tmp/my.db --sync --meta-db /tmp/my-meta.db --meta-namespace meta
Developer Setup
We use uv to manage our development setup.
Start the server with:
uv run sqlrooms-server --db-path /absolute/path/to/my.db
Run uv run ruff check --fix and uv run ruff format to lint the code.
To run the tests, use uv run pytest.
To set up a local certificate for SSL, use https://github.com/FiloSottile/mkcert.
API
The server supports queries via WebSockets only. Minimal HTTP endpoints are provided for health and diagnostics.
Health Endpoints (HTTP)
GET /healthz: returnsokwhen the process is healthy.GET /readyz: returnsokwhen DuckDB is initialized;503otherwise.GET /version: returns JSON with version info.
WebSocket
- URL:
ws://localhost:<port>/ - Messages are JSON text frames unless returning Arrow bytes.
Authentication (optional):
-
If started with an auth token, the client must send the first message:
{"type": "auth", "token": "<TOKEN>"}
-
On success, server replies
{ "type": "authAck" }. Any other message before auth results in an error and the connection is closed.
Supported messages:
-
Query (optional
queryId):{"type":"arrow","sql":"select 1 as x","queryId":"q1"} {"type":"json","sql":"select 1 as x","queryId":"q2"} {"type":"exec","sql":"create table t(x int)","queryId":"q3"}
-
Result correlation (Arrow): binary frame
- Layout:
[4-byte big-endian length][header JSON][arrow bytes] - Header JSON example:
{ "type": "arrow", "queryId": "q1" }
- Layout:
-
Result correlation (JSON/OK): text frame
{"type":"json","queryId":"q2","data":"[{\"x\":1}]"} {"type":"ok","queryId":"q3"}
-
Cancel in-flight query:
{"type": "cancel", "queryId": "q2"}
- Response:
{ "type":"cancelAck","queryId":"q2","cancelled":true } - If the query is already finishing, you may receive the final result instead of an error.
- Response:
-
Subscribe/Notify (server-side notifications):
{"type":"subscribe","channel":"table:orders"} {"type":"notify","channel":"table:orders","payload":{"op":"update"}}
- Subscribe ack:
{ "type":"subscribed","channel":"table:orders" } - Notify:
- Broadcast to subscribers via
app.publish - Immediate echo to the sender:
{ "type":"notify","channel":"table:orders","payload":{"op":"update"} } - Ack:
{ "type":"notifyAck","channel":"table:orders" }
- Broadcast to subscribers via
- Subscribe ack:
Optional sync (CRDT) (requires --sync)
-
Join a room and receive server snapshot:
{"type": "crdt-join", "roomId": "room-1"}
- Responses:
{ "type":"crdt-joined","roomId":"room-1" }and{ "type":"crdt-snapshot","roomId":"room-1","data":"<base64>" }
- Responses:
-
Send binary Loro updates after joining. The server imports them into its LoroDoc, exports a normalized update, broadcasts to the room, and persists a snapshot to the meta storage. Ack:
{ "type":"crdt-update-ack","roomId":"room-1" }
Notes:
- Sync is off by default; enabled only when
--syncis provided. - If
--meta-dbis provided, meta tables (including sync snapshots) are stored in that attached DuckDB file (attached under--meta-namespace). - If
--meta-dbis not provided, meta tables are stored in the main DuckDB under the--meta-namespaceschema.
Concurrency & Cancellation
- DuckDB work runs in a shared thread pool with per-task cursors.
- Per-query cancellation is supported via
duckdb.interrupt. - WebSocket multiplexing uses
queryIdcorrelation in headers/payloads. - One-time retry on transaction conflicts (e.g., concurrent UPDATE vs ALTER).
Notes
- Graceful shutdown: SIGINT/SIGTERM cancel in-flight queries, FORCE CHECKPOINT, close connection, stop executor.
- Auth token can be supplied via CLI
--auth-token.
Publishing
Run the build with uv build. Then test publish with pnpm prerelease. We publish using tokens so when asked, set the username to __token__ and then use your token as the password. Alternatively, create a .pypirc file.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sqlrooms_server-0.1.0.tar.gz.
File metadata
- Download URL: sqlrooms_server-0.1.0.tar.gz
- Upload date:
- Size: 24.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5d4d7a79632902831be8ad8b9922ae6bcbe90726f049977b7ac75c32ab4f6199
|
|
| MD5 |
1ab66a3ceb2e70c589b759d4aeefc96b
|
|
| BLAKE2b-256 |
e30d8aed4d54b7b3e29f1e6abefd9da55a303cf486361b06cfd972ed9d89202e
|
File details
Details for the file sqlrooms_server-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sqlrooms_server-0.1.0-py3-none-any.whl
- Upload date:
- Size: 31.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bd1722b69c23962c58ec360bf755f936d89a1baac2f0c268f9ac5d952ec8f735
|
|
| MD5 |
7bb87a60d9a90f043c373c80fac49d22
|
|
| BLAKE2b-256 |
1edc864f9c8cb20f9e4d7dbd95b6956d7c0ffb2ab29272e3df3d521abc8dab6f
|