WebDuck - DuckDB as a Service with REST API and Web UI<br>WebDuck<br>DuckDB as a Service<br>Fast, simple DuckDB-as-a-Service with REST API and Web UI. Install via pip, deploy with Docker, query your data in seconds.<br>Get StartedView on GitHub
Web UI<br>Dashboard
Projects
Browse View
Quickstart<br>pip<br>pip install webduck# Unix<br>pipx install webduck# macOS
Docker<br>docker run --name webduck<br>-p 8998:8998<br>-v webduck_data:/app/data<br>-e WEBDUCK_ADMIN_USER=admin<br>-e WEBDUCK_ADMIN_PASS=secret<br>autumoswitzerland/webduck
Terminal
Features
REST API<br>Full REST API with JWT auth, optional DB passwords, and project management.
Dashboard<br>Live traffic monitor with queries per second and active sessions, plus a storage overview including trash usage.
DuckDB Engine<br>Built on DuckDB with file-locking for safe concurrent access and fast analytics.
Projects & Data Browser<br>Organize databases into projects, browse tables with infinite scroll, and edit cells in place.
Import/Export<br>CSV, Parquet and JSON import via drag & drop, one-click export with browser download.
SQL Editor<br>Multi-statement SQL editor with query history and SQL file upload, sequential execution.
Compress & Optimize<br>Database size and fragmentation indicators, with compact support to reclaim disk space.
Trash<br>Delete to trash instead of permanently — restore projects and databases with one click.
i18n<br>English + German out of the box, extensible via PO/Gettext.
API Examples<br>Query your data from any language<br>cURLPythonPHPJava<br># Login - get JWT token<br>TOKEN=$(curl -s -X POST http://localhost:8998/admin/login \<br>-H "Content-Type: application/json" \<br>-d '{"username": "admin", "password": "secret"}' | jq -r '.token')
# Create a project<br>curl -X POST http://localhost:8998/admin/projects \<br>-H "Authorization: Bearer $TOKEN" \<br>-H "Content-Type: application/json" \<br>-d '{"name": "myproject"}'
# Create a database<br>curl -X POST http://localhost:8998/admin/projects/myproject/databases \<br>-H "Authorization: Bearer $TOKEN" \<br>-H "Content-Type: application/json" \<br>-d '{"name": "mydb"}'
# Query data — no password = open<br>curl -X POST http://localhost:8998/db/projects/myproject/databases/mydb/query \<br>-H "Content-Type: application/json" \<br>-d '{"sql": "SELECT * FROM users LIMIT 10"}'
# Set DB password (optional — without it, API is open)<br>curl -X PUT http://localhost:8998/admin/projects/myproject/databases/mydb/password \<br>-H "Authorization: Bearer $TOKEN" \<br>-H "Content-Type: application/json" \<br>-d '{"password":"dbpass","access_level":"write"}'
# Query with DB password set<br>curl -X POST http://localhost:8998/db/projects/myproject/databases/mydb/query \<br>-H "Content-Type: application/json" \<br>-H "X-Project-Key: myproject:dbpass" \<br>-d '{"sql": "SELECT * FROM users LIMIT 10"}'<br>import requests
BASE = "http://localhost:8998"
# Login<br>token = requests.post(<br>f"{BASE}/admin/login",<br>json={"username": "admin", "password": "secret"}<br>).json()["token"]<br>headers = {"Authorization": f"Bearer {token}"}
# Create project<br>requests.post(f"{BASE}/admin/projects",<br>json={"name": "myproject"}, headers=headers)
# Create database<br>requests.post(f"{BASE}/admin/projects/myproject/databases",<br>json={"name": "mydb"}, headers=headers)
# Query data — no password = open<br>result = requests.post(f"{BASE}/db/projects/myproject/databases/mydb/query",<br>json={"sql": "SELECT * FROM users LIMIT 10"})<br>print(result.json())
# Set DB password (optional)<br>requests.put(f"{BASE}/admin/projects/myproject/databases/mydb/password",<br>json={"password": "dbpass", "access_level": "write"}, headers=headers)
# Query with DB password set<br>result = requests.post(f"{BASE}/db/projects/myproject/databases/mydb/query",<br>json={"sql": "SELECT * FROM users LIMIT 10"},<br>headers={"X-Project-Key": "myproject:dbpass"})<br>print(result.json())<br>php<br>// Login<br>$login = http_post_json(<br>"http://localhost:8998/admin/login",<br>["username" => "admin", "password" => "secret"]<br>);<br>$token = json_decode($login, true)['token'];<br>$headers = ["Authorization: Bearer $token"];
// Create project<br>http_post_json(<br>"http://localhost:8998/admin/projects",<br>["name" => "myproject"], $headers<br>);
// Create database<br>http_post_json(<br>"http://localhost:8998/admin/projects/myproject/databases",<br>["name" => "mydb"], $headers<br>);
// Query data — no password = open<br>$response = http_post_json(<br>"http://localhost:8998/db/projects/myproject/databases/mydb/query",<br>["sql" => "SELECT * FROM users LIMIT 10"]<br>);<br>print_r(json_decode($response, true));
// Set DB password (optional)<br>http_put_json(<br>"http://localhost:8998/admin/projects/myproject/databases/mydb/password",<br>["password" => "dbpass", "access_level" => "write"], $headers<br>);
// Query with DB password set<br>$response = http_post_json(<br>"http://localhost:8998/db/projects/myproject/databases/mydb/query",<br>["sql" => "SELECT * FROM users LIMIT 10"],<br>["X-Project-Key: myproject:dbpass"]<br>);<br>print_r(json_decode($response, true));<br>var client = HttpClient.newHttpClient();<br>var base = "http://localhost:8998";
// Login<br>var loginReq = HttpRequest.newBuilder()<br>.uri(URI.create(base +...