Why self-host
dbxlite is client-side by design - the container only serves static UI assets (HTML, JS, the DuckDB WASM engine). Queries run in each user's browser tab against their own local and remote files. Nothing is uploaded to the container or to any dbxlite service.
Good fits: internal SQL training, a self-hosted analytics scratchpad, air-gapped/offline environments, or giving a team a shared query tool without provisioning any infrastructure.
Quick Start
docker run -p 8080:80 hfmsio/dbxlite
# then open http://localhost:8080
With Docker Compose:
services:
dbxlite:
image: hfmsio/dbxlite:latest
ports:
- "8080:80"
restart: unless-stopped
docker compose up -d
No volumes, environment variables, or secrets are required for the core DuckDB workflow.
Tags & architectures
latest- most recent releaseX.Y.Z(e.g.0.5.0) - pinned version, recommended for reproducible deploymentsX.Y- latest patch within a minor line
Every tag is a multi-arch manifest for linux/amd64 and linux/arm64 - Intel/AMD servers, Apple Silicon, and ARM cloud instances (AWS Graviton, etc.) all work natively.
Configuration
Port. The container serves on port 80; map it wherever you like (-p 8080:80).
Cross-origin isolation headers (built in). The bundled nginx config sets the headers DuckDB needs for OPFS persistence and file export:
Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: credentialless- keeps the context cross-origin-isolated while still lettinghttpfsfetch remote files/CSVs that don't send CORP headersCross-Origin-Resource-Policy: cross-origin
This is why the Docker image is the recommended path over serving the built assets from a bare web server - omitting these headers silently disables OPFS features. If you put dbxlite behind your own reverse proxy or TLS terminator, preserve these headers.
Behind a reverse proxy / sub-path. Assets are referenced relatively, so the app can be served from any host or sub-path. Terminate TLS at your proxy and forward to the container's port 80.
Server mode still works
The container serves the same UI that DuckDB's ui extension uses, so a user can point a native DuckDB running on their own machine at it for full extensions, unlimited memory, and direct filesystem access:
export ui_remote_url="http://localhost:8080" # this container
duckdb -unsigned -ui # native engine + dbxlite UI on :4213
The engine runs locally next to the user's files; the container only ships the interface. Don't run a shared DuckDB engine inside the container for multiple users - arbitrary SQL implies filesystem and extension access, and a single shared engine has no per-user isolation. Keep the engine on each user's machine. See Server Mode for the full setup.
Health check & operations
- The app is a static site; an HTTP GET on
/returns200when ready. - Stateless - no persistent volumes needed. Restart freely.
- Logs are standard nginx access/error logs on stdout/stderr.
Links
- Docker Hub - full image reference
- GitHub - source, issues, full docs