A DuckDB server with REST API and Web UI
Project description
WebDuck
A self-hosted DuckDB-as-a-Service server with REST API and Web UI. WebDuck is designed for web hosting providers who want to offer their customers a ready-to-use administration interface for DuckDB databases and data analytics — out of the box, just like the database admin tools that come with any hosting package.
Features
- DuckDB storage engine with file-locking for safe concurrent access
- REST API — admin endpoints (project/DB management) + database endpoints (SQL queries)
- Web UI (NiceGUI) — dark mode with yellow/amber theme
- JWT authentication for admin API, optional project-key auth for database access
- bcrypt password hashing (never plaintext)
- SQL editor — multi-statement support with sequential execution
- SQL upload — execute multi-statement SQL scripts from files
- Browse view — tree-based navigation of databases/tables/views with infinite scroll and cell editing
- Import/Export — CSV import via drag & drop, CSV export with browser download
- Project ordering — drag & drop reordering, persisted in
.projects.json - i18n — English (default), German, extensible via PO/Gettext
- Configurable logging — file rotation + console output, independently configurable
- Configurable upload size — max file size for CSV/SQL uploads
- FK dependency hints — DROP errors include referenced tables and constraint info
- Docker support out of the box
- YAML configuration
Web UI
| Projects |
Browse View |
Installation
pip (Python)
pip install webduck
Docker
# docker-compose.yml herunterladen
curl -O https://raw.githubusercontent.com/autumoswitzerland/Webduck/main/docker-compose.yml
# Passwort setzen
export WEBDUCK_ADMIN_PASS=meinpasswort
# Starten (Admin-User wird automatisch angelegt)
docker compose up -d
Quick Start
pip
# Initialisieren (Admin-User anlegen)
webduck init
# Server starten
webduck start
Docker
Docker startet automatisch — UI unter http://localhost:8998/ui/login.
Login mit admin / dem gesetzten Passwort.
CLI Commands
| Command | Description |
|---|---|
webduck init |
Create admin user + default config |
webduck start |
Start the server |
webduck status |
Show projects and databases |
Options:
webduck start --host 127.0.0.1 --port 8080 --config /path/to/webduck.yaml
Configuration
webduck.yaml (generated by webduck init):
icon: "icon.svg"
auth:
jwt_algorithm: HS256
jwt_expire_minutes: 60
jwt_secret: CHANGE-ME-TO-A-SECRET-KEY-IN-PRODUCTION
logging:
file:
enabled: true
level: error
max_files: 5
max_size_mb: 10
query_log: false
log_dir: log
console:
enabled: false
access_log: false
level: warning
server:
data_dir: data
host: 0.0.0.0
port: 8998
max_upload_mb: 5
Web UI Pages
| Page | URL | Description |
|---|---|---|
| Login | /ui/login |
Admin login with language selection |
| Dashboard | /ui/dashboard |
Server status, project/database overview |
| Projects | /ui/projects |
Create/delete projects, manage databases, set passwords, drag & drop reorder |
| Queries | /ui/query |
SQL editor (multi-statement) + SQL file upload |
| Browse | /ui/browse |
Tree navigation, table/view browsing with infinite scroll, cell editing |
| Import/Export | /ui/import |
CSV import (drag & drop) and export (browser download) |
REST API Reference
Admin API (JWT protected)
All admin endpoints require Authorization: Bearer <jwt_token>.
| Method | Endpoint | Description |
|---|---|---|
POST |
/admin/login |
Login, returns JWT token |
GET |
/admin/projects |
List all projects (ordered) |
POST |
/admin/projects |
Create project |
DELETE |
/admin/projects/{project} |
Delete project + all databases |
POST |
/admin/reorder-projects |
Reorder projects |
GET |
/admin/projects/{project}/databases |
List databases in project |
POST |
/admin/projects/{project}/databases |
Create database |
DELETE |
/admin/projects/{project}/databases/{db} |
Delete database |
PUT |
/admin/projects/{project}/databases/{db}/password |
Set database password |
GET |
/admin/users |
List admin users |
POST |
/admin/users |
Create admin user |
DELETE |
/admin/users/{username} |
Delete admin user |
Database API (project-key protected)
All database endpoints require X-Project-Key: <project>:<password>.
Databases without a password set are publicly accessible.
| Method | Endpoint | Description |
|---|---|---|
GET |
/db/projects |
List all projects (public) |
GET |
/db/projects/{project}/databases |
List databases (public) |
POST |
/db/projects/{project}/databases/{db}/query |
Execute SQL (read-only) |
POST |
/db/projects/{project}/databases/{db}/write |
Execute SQL (read-write) |
GET |
/db/projects/{project}/databases/{db}/tables |
List tables + columns |
POST |
/db/projects/{project}/databases/{db}/import |
Import CSV |
GET |
/db/projects/{project}/databases/{db}/export |
Export table to CSV |
Example: Login + Query
# Login
TOKEN=$(curl -s -X POST http://localhost:8998/admin/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"secret"}' | jq -r '.access_token')
# Create project + database
curl -X POST http://localhost:8998/admin/projects \
-H "Authorization: Bearer $TOKEN" \
-d '{"name":"myapp"}'
curl -X POST http://localhost:8998/admin/projects/myapp/databases \
-H "Authorization: Bearer $TOKEN" \
-d '{"name":"main"}'
# Set database password (optional — without password, API is open)
curl -X PUT http://localhost:8998/admin/projects/myapp/databases/main/password \
-H "Authorization: Bearer $TOKEN" \
-d '{"password":"dbpass","access_level":"write"}'
# Execute a query via the Database API
curl -X POST http://localhost:8998/db/projects/myapp/databases/main/write \
-H "X-Project-Key: myapp:dbpass" \
-H "Content-Type: application/json" \
-d '{"sql":"CREATE TABLE users (id INT, name VARCHAR); INSERT INTO users VALUES (1, '\''Alice'\'');"}'
# Read (with password)
curl -X POST http://localhost:8998/db/projects/myapp/databases/main/query \
-H "X-Project-Key: myapp:dbpass" \
-d '{"sql":"SELECT * FROM users"}'
# Read (without password — no header needed)
curl -X POST http://localhost:8998/db/projects/myapp/databases/main/query \
-d '{"sql":"SELECT * FROM users"}'
Docker
docker compose up -d
The data directory is mounted at ./data. Initialize with:
docker compose exec webduck webduck init
Architecture
FastAPI ──┬── /admin/* (JWT auth) → Project/DB management
├── /db/* (project key) → SQL queries + CSV import/export
├── /ui/* (cookie) → NiceGUI Web UI
├── /api/* (session) → Internal UI endpoints
└── /health → Health check
- Storage: DuckDB files in
data/<project>/<database>.duckdb - Project order: Persisted in
data/.projects.json - Auth: Admin passwords in
data/.users.json(bcrypt), DB passwords indata/<project>/.project.json - User preferences: Stored in
data/.user_preferences.json - Logging: Rotated log files in
log/(configurable), independent console logging - Concurrency: Single-writer via file-level locks (apps manage write contention)
Development
git clone https://github.com/autumoswitzerland/Webduck.git
cd webduck
python3.13 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run linter
ruff check src/ tests/
Donate
WebDuck is free and open-source. If you find it useful, consider supporting the development:
License
MIT — see LICENSE for details.
Copyright © 2026 autumo GmbH
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 webduck-1.0.1.tar.gz.
File metadata
- Download URL: webduck-1.0.1.tar.gz
- Upload date:
- Size: 315.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
14d65827e4632d595704f3a026005aa4068f4fc4d68bc0254f5376a2aa3d89d6
|
|
| MD5 |
4f8d065abb2c8082481425c0767bf0df
|
|
| BLAKE2b-256 |
baa3681e9b99fa739c6d651e4ec3cc6f67750c35331e077edc0df544497ac328
|
Provenance
The following attestation bundles were made for webduck-1.0.1.tar.gz:
Publisher:
publish-py.yml on autumoswitzerland/Webduck
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
webduck-1.0.1.tar.gz -
Subject digest:
14d65827e4632d595704f3a026005aa4068f4fc4d68bc0254f5376a2aa3d89d6 - Sigstore transparency entry: 2255234042
- Sigstore integration time:
-
Permalink:
autumoswitzerland/Webduck@c6879f52934a32a4560137773ac3324ad06dc6e3 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/autumoswitzerland
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-py.yml@c6879f52934a32a4560137773ac3324ad06dc6e3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file webduck-1.0.1-py3-none-any.whl.
File metadata
- Download URL: webduck-1.0.1-py3-none-any.whl
- Upload date:
- Size: 318.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
75601236db57c3e0b841be02dc56b98e55a5774b05b9159c7bd40ae47c4dedf3
|
|
| MD5 |
9431d6544f8bc599194e0bb6dc39091e
|
|
| BLAKE2b-256 |
ced1b075e835d48ece0cc175131c77b9e46d3ffd5e71d6e8e739a5eb5ec353a9
|
Provenance
The following attestation bundles were made for webduck-1.0.1-py3-none-any.whl:
Publisher:
publish-py.yml on autumoswitzerland/Webduck
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
webduck-1.0.1-py3-none-any.whl -
Subject digest:
75601236db57c3e0b841be02dc56b98e55a5774b05b9159c7bd40ae47c4dedf3 - Sigstore transparency entry: 2255234045
- Sigstore integration time:
-
Permalink:
autumoswitzerland/Webduck@c6879f52934a32a4560137773ac3324ad06dc6e3 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/autumoswitzerland
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-py.yml@c6879f52934a32a4560137773ac3324ad06dc6e3 -
Trigger Event:
push
-
Statement type: