Portainer Templates logo

Portainer Templates

LibreDB Studio LibreDB Studio

Container

DatabaseTools

Web-based SQL IDE for sixteen database engines, with a schema browser, ER diagrams and query history. Source: https://github.com/libredb/libredb-studio

Image details

Architecture: amd64, arm64
Image size: 198 MB
User: libredb

Source details

Stars: 809
Forks: 157
Language: TypeScript
License: MIT
Updated: 5 minutes ago
Website: libredb.org/

Configuration

Type
Container
Platform
linux
Image
ghcr.io/libredb/libredb-studio:latest
Ports
3000:3000/tcp
Volumes
/app/data
Restart
unless-stopped

Notes

On first run LibreDB Studio generates the admin password and writes it once to the container logs (docker logs libredb-studio). Sign in as [email protected] with that password. Connections and query history are kept in the /app/data volume. Reaching it over plain HTTP on a LAN address needs AUTH_COOKIE_SECURE=false, otherwise login fails while the container stays healthy.

Standalone Install

Select an install method, to see config/commands for deploying LibreDB Studio

Installation method

Install on Portainer

Import all app templates into your Portainer instance, for easy 1-click deploys

  1. Ensure both Docker and Portainer are installed, and up-to-date
  2. Log into your Portainer web UI
  3. Under Settings → App Templates, paste the below URL
  4. Head to Home → App Templates, and the list of apps will show up
  5. Select LibreDB Studio, fill in any config options, and hit Deploy

Template Import URL

https://raw.githubusercontent.com/Lissy93/portainer-templates/main/templates.json
Show Me demo

More install options in our documentation, or see libredb/libredb-studio for app-specific guidance.

LibreDB Studio Logo


LibreDB Studio


The database editor that deploys next to your data, not onto your laptop.


English · 简体中文 · 日本語 · Español · اردو · हिन्दी


Listed by the PostgreSQL project: News · PostgreSQL Clients · Software Catalogue · Community Guide to GUI Tools

Also listed in official Redis, ClickHouse, MariaDB, Trino, Apache Cloudberry, YugabyteDB, DragonflyDB and OpenSearch docs


Opening a table, running a join, charting the result and reading the ER diagram in LibreDB Studio


GitHub stars License: MIT Quality Gate Coverage DeepWiki Docs Artifact Hub


Next.js 16 React 19 Docker Support Kubernetes Compatible


Quick StartLive DemoInstall OptionsDeploy Your Own


Quick Start

Run a full Database Editor in one command, no clone, no build:
# Docker (recommended)
docker run -p 3000:3000 ghcr.io/libredb/libredb-studio:latest

# or with Node.js 24+ (no Docker)
npx @libredb/studio

Then open http://localhost:3000. On first run, the admin password is printed to the log (zero-config).
If the browser reaches Studio at anything other than localhost or HTTPS (http://192.168.x.x:3000 on a LAN, for example), also set AUTH_COOKIE_SECURE=false. Without it the health check passes while login fails silently and sends you back to the login page.

Need Helm, Homebrew, Snap, winget, or deb/rpm? See all install options.

Live Test

Try LibreDB Studio instantly without installation!

TestURLCredentials
Public Test With OIDCapp.libredb.orgSSO
Public Test With JWTtrial.libredb.org[email protected] / Admin!2026 [email protected] / User!2026

The test instance comes with a pre-configured PostgreSQL database via Seed Connections. No setup required!

Overview

You create a Postgres on a managed platform. It is ready in forty seconds. Then you want to look inside it — so you open a port to the internet, dig an SSH tunnel, or install a desktop client on every machine that needs one.
LibreDB Studio goes the other way. It deploys next to the data: a container, a Helm chart, an operator, a one-click template on your PaaS, or npm i @libredb/studio inside your own product. Nothing has to face outward.
Sixteen engines share one interface — PostgreSQL, MySQL, Oracle, SQL Server, SQLite, libSQL, DuckDB, MongoDB, Redis, Couchbase, ClickHouse, Druid, Elasticsearch, OpenSearch, Apache Trino and Apache Cassandra — with the same explorer everywhere, and ER diagrams, schema diff and monitoring wherever the engine has something to report. Three of the sixteen are read-only because their own SQL is: Druid, Elasticsearch and OpenSearch have no UPDATE and no CREATE TABLE in the grammar at all, so those controls are reported as unsupported instead of failing when used. Cassandra is the newest, and the one that reports the least on purpose: it publishes no row count and no size that is true, so the object browser shows neither rather than showing a number that is wrong — the estimate it does publish counts partitions from flushed files, and it read 143 for a 500-row table. Trino is the other odd one: it is a query engine rather than a database, so it declares no keys and no indexes and reports the bytes as belonging to the systems behind its connectors.
And nothing is held back. Single sign-on, ER diagrams, the AI features and the NoSQL engines all ship in the MIT build. MIT is not generosity here, it is a requirement of the architecture: you cannot place a per-seat licensed, feature-gated tool into every environment you own.

Why LibreDB Studio?

  • Deploys next to the data: container, Helm chart, Rancher, OpenShift operator, one-click PaaS template, or embedded via npm.
  • Sixteen engines, one interface: PostgreSQL, MySQL, Oracle, SQL Server, SQLite, libSQL, DuckDB, MongoDB, Redis, Couchbase, ClickHouse, Druid, Elasticsearch, OpenSearch, Trino, Cassandra.
  • Runs where you are: browser, phone, Windows, MacOS, Linux desktop.
  • A read-only agent, with your own model: state a question, and the run drafts SQL, reads the results, and writes a report whose claims cite them. Gemini, OpenAI, or a local Ollama with open-source models.
  • Nothing behind a wall: RBAC, OIDC single sign-on, query audit trail, and ER diagrams all ship under MIT.

Multi-Database Connection Manager
Connect to PostgreSQL, MySQL, Oracle, SQL Server, MongoDB, Couchbase, ClickHouse, Druid, Elasticsearch, OpenSearch, Trino, Cassandra, Redis, SQLite, DuckDB, or libSQL with SSL/TLS and SSH Tunnel support.


Ask DeepWiki

Key Features

Professional SQL IDE

  • Monaco Engine: Powered by the same core as VS Code.
  • Smart Autocomplete: Schema-aware suggestions for tables, columns, and SQL keywords.
  • Command Palette: Quick access to tables, connections, saved queries, and actions with Cmd/Ctrl+K.
  • Multi-Tab Workspace: Handle parallel tasks with independent execution states.
  • Saved Query Backups: Export the complete saved-query library as JSON. Import validates the file, preserves query metadata and merges new entries, reporting duplicate IDs while keeping existing queries intact.
  • Duplicate Connections: Open an independent (copy) of an editable saved connection in the connection editor, adjust its settings and save. Cancelling leaves the saved connections unchanged; administrator-managed connections cannot be duplicated.
  • Visual EXPLAIN: Graphical execution plans to identify performance bottlenecks.
  • Interactive ER Diagrams: Visual schema graph with real foreign key edges, cardinality labels, MiniMap navigation, table search/filter, compact mode, and PNG/SVG export. Automatic hierarchical layout powered by ELK.js.
  • Schema Diff & Migration: Compare schema snapshots or cross-connection schemas side-by-side. Color-coded diff view (added/removed/modified) with automatic migration SQL generation for PostgreSQL, MySQL, SQLite, Oracle, and SQL Server, plus ClickHouse column modifications.
  • Snapshot Timeline: Visual horizontal timeline of schema snapshots. Click any two points to instantly compare and track schema evolution over time.

Interactive ER Diagram
Visual schema explorer with interactive ER diagrams powered by ReactFlow.

The Database Agent

Studio's main AI surface is an agent rail beside the editor; the model-backed helpers listed below it are the others. You state an objective: "which department has the most employees?", "why is this query slow?"; and press Start. The run drafts SQL against the connected database, reads what comes back, and finishes by composing a report whose every claim cites the result it came from.
  • Read-only, enforced by the database rather than by a parser. Every statement the agent runs
goes through the agent's own audited pipeline — a policy decision, an audit event and budget accounting before the driver is touched (executeAuditedOperation, src/lib/db/operations/execution.ts:129) — under a read-only execution profile: a read-only transaction on PostgreSQL, PRAGMA query_only re-asserted per statement on SQLite, a READ_ONLY engine handle on DuckDB paired with an SQL-level guard, because that flag alone still lets COPY … TO, EXPORT DATABASE and the local-file table functions through, and, on SQL Server, which has no read-only transaction of any kind, a session principal verified at open to be unable to write, an optimizer admission that compiles each statement without running it, a server-side row bound, and a transaction that is always rolled back. Writes and DDL are refused before the database is reached, and EXPLAIN ANALYZE is default-denied because it would run the statement. This pipeline is the agent's alone: statements you run yourself in the editor call the provider directly (src/app/api/db/query/route.ts:44) and are neither policy-checked nor audited this way.
  • Agent mode reads PostgreSQL, SQLite, DuckDB and SQL Server only. The read-only profile is
database-native, so it exists only where a provider implements it — queryReadOnly on postgres.ts, sqlite.ts, duckdb/index.ts and mssql.ts, and nowhere else. On any other engine an Agent-mode run whose workflow sends statements is refused when it is started, before a run is opened, and any that reaches the provider factory ends engine-unsupported. Plan mode opens on every connection — the model there is toolless, runs no statement of yours, writes nothing, and drafts a statement for you to run yourself. Its GROUNDING reaches every engine: on PostgreSQL and SQLite the server composes catalog statements itself, and on every other connection it asks that connection's own provider to describe its schema — the reading the sidebar already performs — which needs no read-only statement path. So the two limits are separate: agent mode is those four engines, grounding is all of them, and a run whose reading fails says so plainly rather than inventing tables.
  • Three workflows: Investigate (answer a question), Optimize (compare estimated plans,
propose an index or a rewrite), Assess (profile tables — counts only, never values).
  • Nothing runs itself. The agent never starts a run for you, never writes to the editor, and
never executes what it recommends. Applying a statement is your click.
  • Evidence or nothing. A claim with no citation cannot be composed, and the run states its own
verdict — "Run answered" or "Run did not answer" — beside how it ended.
  • Bounded, and the meter is on screen: 18 to 45 statements and a 360 s to 900 s run deadline
depending on workflow, 200 rows per read. See docs/AGENT.md for the exact figures per workflow.
  • Your own model. Gemini (the default), OpenAI, Ollama, or any OpenAI-compatible endpoint.
Agent mode needs a model that can call tools — on Ollama, a live probe, not the vendor's page, is what establishes that, and the guide says how to run one. Plan mode needs no tools and is never probed (src/lib/agent/capability-gate.ts:74), so a model refused for Agent mode can still be used in Plan mode, which is what the rail offers you.
  • No model configured, no AI. With no LLM_* settings at all, the rail does not render, and
nothing leaves your network. Note that a key is not the switch: Ollama and a custom endpoint count as a configured model without one, and then the AI is on. What the agent sends is docs/AGENT_DATA_FLOW.md.
Standalone application only: the embedded @libredb/studio package carries no agent surface. Guide: docs/AGENT_GUIDE.md · What leaves the machine: docs/AGENT_DATA_FLOW.md · Behaviour and limits: docs/AGENT.md · Which local model to run: docs/llms/

Model-backed helpers

  • Universal LLM Support: Defaults to Gemini and serves OpenAI, Ollama, and any OpenAI-compatible endpoint (LM Studio, LiteLLM, vLLM).
  • Query Safety Analysis: AI-powered pre-execution risk assessment for destructive queries (DELETE, DROP, TRUNCATE). With no provider configured, the confirmation remains available with a plain query warning. Setting LLM_PROVIDER without its credentials is an unfinished setup, so that error stays visible, as do other configuration and service errors.
  • AI Query Explainer: EXPLAIN plans translated into plain language with optimization suggestions.
  • Schema Awareness: the connected database's schema is sent as context, so an explanation names your own tables and columns.
  • Data Profiler summary: the profiler's per-column statistics written up in prose. That context carries each column's min and max, which are real values from your data; see Agent Data Flow.

Pro Data Management

  • Universal Data Grid: Virtualized rendering (TanStack) for millions of rows.
  • Inline Editing: Double-click to update values directly in the grid, on engines whose SQL has a single-table row update (the control is hidden elsewhere).
  • Column Filtering: Per-column text filters on query results for instant data exploration.
  • Interactive Pivot Table: Client-side pivoting with 5 aggregation functions (COUNT, SUM, AVG, MIN, MAX) and SQL generation.
  • Expert Exporter: Instant CSV and JSON exports for reporting. CSV import and result export offer comma (default), semicolon and tab separators. Every format the Export menu writes to a file it also copies straight to the clipboard.

Advanced Data Visualization

  • 8 Chart Types: Bar, Line, Pie, Area, Scatter, Histogram, Stacked Bar, and Stacked Area charts powered by Recharts.
  • Data Aggregation: Group-by with SUM, AVG, COUNT, MIN, MAX aggregation functions. Date grouping by hour, day, week, month, or year.
  • Chart Persistence: Save chart configurations and reload them instantly. Manage a library of saved charts.
  • Chart Dashboard: Grid view of all saved charts for at-a-glance data overview directly in the bottom panel.

Display Masking (Preview)

  • Client-Side Display Layer: Masks sensitive values in the browser UI — useful for screen sharing, demos, and reducing accidental on-screen exposure. Not server-enforced; query API responses still contain full values for authenticated users.
  • Column-Name Pattern Matching: 10 built-in patterns (email, phone, credit card, SSN, password, IP, date, financial, and more) match result column headers by regex. Works when the output name matches (e.g., SELECT salary). Aliases (salary AS x) and aggregates (SUM(salary)) are not masked today.
  • Configurable Rules: Admin panel to add, edit, enable/disable masking patterns. Email, phone, credit card and SSN presets prefill the Add Pattern form so column patterns can be adapted before saving. Custom patterns support regex. Settings stored per-browser in localStorage.
  • RBAC UI Controls: User role cannot toggle or reveal masked cells in the UI. Admin role can toggle masking and temporarily reveal individual cells (10s auto-hide).
  • Export & Clipboard: CSV, JSON, and SQL INSERT exports, whether saved as a file or copied to the clipboard, use masked display values when masking is active in the UI. This does not prevent access to raw data via the API, browser DevTools, or admin reveal.
  • UI Coverage: Grid, mobile card/table views, row detail sheet, and clipboard copy respect the active display mask.

Analyst & Developer Tools

  • AI Data Profiler: One-click table profiling with column statistics (null %, cardinality, min/max, sample values) and AI-powered narrative summaries.
  • ORM Code Generator: Generate TypeScript interfaces, Zod schemas, Prisma models, Go structs, Python dataclasses, and Java POJOs from live table schemas.
  • Test Data Generator: Schema-aware fake data generation with 30+ semantic column inferences (email, phone, name, address, etc.). Produces INSERT statements or MongoDB insertMany JSON.
  • Database Documentation: Auto-generated searchable data dictionary from live schema with AI-powered documentation and Markdown export.

AI Data Profiler
One-click column profiling: null %, cardinality, min/max, and sample values for 300K+ rows.


ORM Code Generator
Generate TypeScript interfaces, Prisma models, Go structs, and more from live schemas.

Authentication & SSO

  • Dual Auth Modes: Local email/password login or OpenID Connect (OIDC) Single Sign-On; switchable via environment variable.
  • Vendor-Agnostic OIDC: Works with any OIDC-compliant provider — Auth0, Keycloak, Okta, Azure AD, Zitadel, Google, and more.
  • One-Command SSO Demo: docker compose -f docker-compose.oidc-demo.yml up starts Studio with a preconfigured Keycloak so you can try SSO and role mapping locally (walkthrough).
  • PKCE Security: Authorization Code Flow with Proof Key for Code Exchange (S256) for secure authentication.
  • Auto Role Mapping: Configurable claim-based role mapping with dot-notation for nested claims (e.g., realm_access.roles).
  • Provider Logout: Logout clears both the local JWT session and identity provider session.

DBA Maintenance Toolkit (Admin Only)

  • Live Monitoring Dashboard: 7-tab monitoring with Overview, Performance, Queries, Sessions, Tables, Storage, and Connection Pool views.
  • Time-Series Trend Charts: Real-time metric trends (connections, cache hit ratio, buffer pool, deadlocks) with auto-refreshing ring buffer history.
  • Configurable Auto-Refresh: Polling intervals from 5s to 60s with play/pause control.
  • Threshold Alerting: Color-coded health indicators (healthy/warning/critical) for cache hit ratio, connection usage, deadlocks, and buffer pool utilization.
  • Connection Pool Stats: Live total/active/idle/waiting pool metrics with utilization progress bars.
  • One-Click Maintenance: Trigger VACUUM, ANALYZE, REINDEX, UPDATE STATISTICS, DBCC CHECKDB, and ALTER INDEX REBUILD per database engine.
  • Audit Trail: Full history of every query executed across the organization. The admin Audit tab exports loaded operations and query history as CSV or JSON, respecting the current filters.

Supported Databases

DatabaseDriverFeatures
PostgreSQLpgFull SQL IDE, EXPLAIN plans, transactions, query cancellation (pgcancelbackend)
MySQLmysql2Full SQL IDE, EXPLAIN plans, transactions, query cancellation (KILL QUERY)
Oracleoracledb (Thin mode)Full SQL IDE, FETCH FIRST N ROWS pagination, V$ monitoring views, ANALYZE TABLE, ALTER INDEX REBUILD, transactions
SQL Servermssql (tedious)Full SQL IDE, TOP N / OFFSET FETCH pagination, sys.dm DMVs, UPDATE STATISTICS, DBCC CHECKDB, transactions, Azure SQL auto-detect
SQLitebun:sqlite / node:sqlite (runtime-selected)Full SQL IDE, file-based or in-memory databases (server-local file)
libSQLnone — HTTP (the Hrana protocol, POST /v2/pipeline, port 8080)Full SQL IDE against a libSQL server or Turso Cloud — the same SQLite dialect as the row above, reached across a network instead of on disk. EXPLAIN QUERY PLAN, sqlitemaster and pragma introspection, and real per-table bytes from dbstat, which the file-based driver above cannot read. The credential is an auth token rather than a password. Two maintenance operations only, REINDEX and PRAGMA integritycheck: the server refuses VACUUM, ANALYZE, PRAGMA optimize and PRAGMA walcheckpoint outright, so no control is offered for them
DuckDB@duckdb/node-api (a native N-API addon, ~68 MB of platform bindings)Full SQL IDE against a local DuckDB file or :memory:, on the server the app runs on. EXPLAIN (FORMAT JSON) physical plan trees, duckdb catalog introspection, real per-table bytes from pragmastorageinfo block allocation, and query cancellation through the driver's own interrupt(). Three maintenance operations, VACUUM, ANALYZE and CHECKPOINT: REINDEX is a parser error here and neither PRAGMA integritycheck nor PRAGMA optimize exists, so no control is offered for them. No slow-query log and no session list — DuckDB publishes neither, so those panels say so rather than showing a zero. The file admits exactly ONE operating-system process, refused in read-only mode too, so a second Studio instance cannot open a database this one holds
MongoDBmongodbJSON query editor, collection operations (find, aggregate, insert, update, delete)
Couchbasenone — HTTP (Query + management REST)Full SQL++ IDE, EXPLAIN plans, bucket/scope/collection explorer, INFER column inference, read-your-writes consistency, UPDATE STATISTICS / BUILD INDEX / request kill
ClickHousenone — HTTP (SQL interface, port 8123)Full SQL IDE, JSON EXPLAIN plan trees, system-table schema introspection, OPTIMIZE TABLE / table statistics / query kill maintenance
Apache Druidnone — HTTP (POST /druid/v2/sql, Router port 8888 or Broker 8082)Read-only SQL IDE, native-query EXPLAIN plan trees, INFORMATIONSCHEMA datasource introspection, sys. monitoring (segments, servers, ingestion tasks). Druid SQL has no UPDATE, no DELETE and no CREATE TABLE, and nothing it can do counts as a maintenance operation — a datasource changes through ingestion, not from the editor
Elasticsearchnone — HTTP (POST /sql?format=json, port 9200)Read-only SQL IDE, mapping-driven index/field explorer, cluster health plus per-index document counts and store sizes. No EXPLAIN, no maintenance operation, no slow-query or session panel: those live in log files and stats APIs the SQL surface does not reach. Elasticsearch SQL also has no OFFSET, so a second page of results cannot be requested — narrow the statement or raise the limit instead
OpenSearchnone — HTTP (POST /plugins/sql, port 9200)The same read-only SQL IDE and explorer, from the same provider module. LIMIT n OFFSET m does work here, so paging does
Apache Trinonone — HTTP (the client protocol, POST /v1/statement, port 8080)Full SQL IDE across every configured catalog, EXPLAIN (FORMAT JSON) plan trees, informationschema schema tree for the catalog the connection pins, system.runtime + jmx monitoring, real SHOW STATS row counts, query cancellation and killquery maintenance. Trino is a query engine and stores nothing, so it declares no primary keys, no foreign keys and no indexes anywhere — the ER diagram draws boxes and no edges, inline row editing is switched off, and the size panels name the catalogs rather than inventing a footprint. A failed statement arrives as HTTP 200, and a password is refused over plain HTTP even on a cluster with authentication disabled
Apache Cassandracassandra-driver (pure JS, no native module)CQL IDE over the native protocol (port 9042), keyspace browser marking partition and clustering keys, systemviews overview, uptime and running statements. No EXPLAIN (the keyword is not in CQL), no cancellation (the protocol has none), no maintenance (every operation is a nodetool action), and no row counts or sizes: the only figures Cassandra publishes are partition estimates from flushed files and whole mebibytes, so neither is shown rather than shown wrong
RedisioredisCommand editor, key browser, INFO-based monitoring

Twenty-six more engines have no driver of their own. The sixteen above are the drivers this build ships. Twenty-six further engines speak one of those wire protocols and connect through an existing driver unchanged, so sixteen drivers reach forty-two named engines in all. They are MariaDB, Percona Server for MySQL, TiDB, Vitess, StarRocks, Apache Doris, OceanBase, SingleStore, Databend, Citus, Percona Distribution for PostgreSQL, ParadeDB, OrioleDB, TimescaleDB, YugabyteDB, AlloyDB Omni, Apache Cloudberry (incubating), CockroachDB, Materialize and RisingWave (as PostgreSQL or MySQL), Valkey, DragonflyDB, KeyDB and Garnet (as Redis), FerretDB (as MongoDB), and ScyllaDB (as Cassandra). Each was measured against a live instance, and how much of the product works differs per engine. MariaDB, both Percona distributions, TiDB, Vitess, AlloyDB Omni, Citus, TimescaleDB, YugabyteDB, ParadeDB, OrioleDB, Valkey, DragonflyDB, KeyDB and FerretDB behave as their driver's own engine, though three of them report statistics you should not trust: a Citus distributed table and a TimescaleDB hypertable report row counts and sizes that are wrong rather than missing, and YugabyteDB reports 0 until you run ANALYZE. Vitess is not one of those three, its row counts and sizes being exact to the byte, but a running query cannot be cancelled there: vtgate refuses KILL QUERY and the statement runs to completion. AlloyDB Omni is not one of them either, reporting 2000 rows for 2000 and 270336 bytes for 270336, but two things there surprise: version() names AlloyDB nowhere, so the version panel cannot be told apart from a stock PostgreSQL 17, and eight of AlloyDB's own google_ml tables list in the object browser, which any role that can connect at all may also read. StarRocks reports itself as MySQL 5.1 and loses its overview, health and session panels, its monitoring dashboard rendering six panels with the session one carrying the engine's own refusal; Apache Doris - the engine StarRocks is a fork of - loses only the overview and health panels, to one statement form its grammar rejects, and is the more trustworthy of the two where it counts: it reports 2000 rows and 10187 bytes for a table holding exactly that, where StarRocks reads zero at first too - its own background statistics collector is slower, measured 4.5 minutes against 3.3.22 where Doris's is about a minute - and, until a 2026-09-16 fix, read zero forever afterward for sizes specifically, because StarRocks' INDEX_LENGTH is NULL rather than Doris's real 0 and poisoned the sum the provider computed in SQL; no index is ever reported, and a foreign key is accepted, listed by SHOW CONSTRAINTS, invisible to the ER diagram and unenforced; Cloudberry loses the monitoring dashboard and its table and index statistics, all three to one MPP planner restriction, and reads a foreign key back as though it were enforced when it is not, though its row counts are correct; CockroachDB loses the object browser and the size panels; OceanBase answers fourteen of the fifteen surfaces but only twelve of them usefully, health failing outright because its tenant has no performance_schema database at all and every size reading 0 B, though its row counts are correct once ANALYZE TABLE has run; SingleStore lost five surfaces to a cause that was ours rather than its own - the provider sent every statement through the prepared-statement protocol, which SingleStore refuses for the SHOW and EXPLAIN statements four panels need - and four of those five are now recovered, its Explain panel being the one that is not, because there the grammar wants EXPLAIN JSON and the statement fails on either protocol; its numbers are still missing rather than wrong, a 2000-row table reading 0 rows and 0 B with no ANALYZE able to change it; ScyllaDB loses five surfaces and Test Connection with them, all six to one absent keyspace - the overview, health, performance-metrics, active-session and monitoring panels read Cassandra's system_views virtual tables and ScyllaDB has no system_views keyspace at all - those five now degrade to empty rather than throwing, so Test Connection passes and the dialog saves the connection, which it could not do at all until that change - while the editor and the object browser work in full, every one of 18 CQL types reading back byte-identically to the Cassandra 5.0.9 probed in the same pass; ParadeDB and OrioleDB are both full and their costs are opposites: ParadeDB's nine extensions put 41 objects in the object browser for 2 user tables and break agent plan mode on a stock install, while OrioleDB's browser is clean and its own storage is invisible to PostgreSQL's size functions, so every index reads 0 bytes and the cache hit ratio reads N/A. Materialize, RisingWave and Databend are query-editor-only, and Databend is the one of those three whose catalogs answer perfectly well when asked directly - the object browser is empty because our parameterised reads use a prepared protocol it does not implement. Garnet behaves as Redis and is one of three relatives here (with Valkey and DragonflyDB) whose own version INFO carries beside the Redis compat level and the overview now labels ahead of it - Garnet 2.1.5 (Redis 7.4.3) - and two of its readings are absences wearing a value, every size showing 0 B because it publishes no used_memory and the cache hit ratio showing 100% because it publishes no keyspace counters. The per-engine detail, with the exact version probed, is in docs/providers/README.md — we publish a name only after connecting to it, so a name absent there is untested rather than unsupported.

Transport security is cross-cutting, not per engine. The SSH tunnel is opened before the provider connects and the connection is rewritten to the local endpoint, so it is provider-independent: it applies to any connection configured with a host and a port. A connection entered as a connection string instead (an option for MongoDB, Couchbase, ClickHouse and libSQL) carries neither, so it is not tunnelled; SQLite and DuckDB have neither either. The SSL/TLS panel is honoured by every engine that shows it — which is every engine except the three file-based ones, SQLite, DuckDB and the embedded LibreDB, where no transport exists to secure and no panel is offered. On Trino it is load-bearing rather than optional, because the coordinator refuses a password over plain HTTP. Oracle is the one engine whose mapping carries a caveat worth stating up front: its Thin driver always verifies the certificate chain, so require needs the server's CA supplied when that certificate is self-signed, and a connect string pasted whole keeps whatever protocol it names.

All SQL databases share: schema explorer, ER diagrams, schema diff & migration, display masking (preview), monitoring dashboard, and connection string import. Druid, Elasticsearch, OpenSearch and Trino are each the exception twice over: their HTTP SQL APIs have no URI convention this build can parse, so they are configured by host and port only, and a generated migration names the limitation instead of emitting column-modification DDL against an engine whose SQL contains none — as it also does for Couchbase's schemaless collections. An ER diagram over a search cluster draws boxes and no edges: an index declares no foreign keys and the engine's model has none to declare, which the provider states as declaresForeignKeys: false rather than leaving to be guessed from an empty list.

Provider reference docs: each database has an in-depth reference (design, connection, query format, monitoring, limitations) under docs/providers/. For the provider architecture see docs/DATABASE_PROVIDERS.md, and to add a new database see docs/ADDING_A_PROVIDER.md.

Tech Stack

ComponentTechnologyTarget
FrameworkNext.js 16 (App Router), React 19Web, Mobile
UI EngineTailwind CSS 4, Radix UI, shadcn/uiWeb, Mobile
ThemingCSS Variables + @theme inline (Guide)Web, Mobile
EditorMonaco Editor (VS Code Engine)Web
AIMulti-Model (Gemini, OpenAI, Ollama, Custom)Web, Mobile
AuthJWT (jose) + OIDC (openid-client), PKCE, Role MappingWeb, Mobile
DatabasePostgreSQL, MySQL, Oracle, SQL Server, SQLite, libSQL, DuckDB, MongoDB, Couchbase, ClickHouse, Apache Druid, Elasticsearch, OpenSearch, Apache Trino, Apache Cassandra, RedisWeb, Mobile
ChartsRecharts (Bar, Line, Pie, Area, Scatter, Histogram, Stacked)Web, Mobile
ERDReact Flow, ELK.js (auto-layout)Web
State/GridTanStack Table & VirtualWeb, Mobile
DeploymentDocker, KubernetesWeb

Getting Started

### Install
ChannelCommandNotes
Dockerdocker run -p 3000:3000 ghcr.io/libredb/libredb-studio:latestZero-config: the admin password is printed to the log on first run
Helm (Kubernetes)helm install libredb oci://ghcr.io/libredb/charts/libredb-studioZero-config: first-run admin credentials are printed to the pod log
npxnpx @libredb/studioLinux/macOS/Windows, Node 24+ (24 LTS is the reference runtime); downloads the release server archive
Homebrewbrew trust libredb/tap && brew install libredb/tap/libredb-studiobrew trust is required once (Homebrew 6+; run brew update if unknown)
deb / rpmsudo dpkg -i libredb-studio<version>amd64.debAttached to each GitHub release; systemd service included
Snapsudo snap install libredb-studioZero-config: the admin password is printed to sudo snap logs libredb-studio on first run — Snap Store listing
winget (Windows)winget install LibreDB.StudioPortable zip with a bundled Node.js runtime; run libredb-studiolisted in the winget community repository
Chocolatey (Windows)choco install libredb-studioSame standalone zip — listed in the Chocolatey community repository; the first push (0.9.59) cleared moderation on 2026-08-24, and every release publishes automatically since (#114)
Portable zip (Windows).\libredb-studio.exeDownload from GitHub Releases; bundled Node runtime, no package manager needed
Desktop app (Linux, AppImage)chmod +x libredb-studio-desktop-<version>-linux-x64.AppImage && ./libredb-studio-desktop-<version>-linux-x64.AppImageNative window, no browser tab and no login prompt; the server runs as a local sidecar. For a sandboxed build, use the Flatpak row below (#232)
Desktop app (Debian/Ubuntu)sudo apt install ./libredb-studio-desktop-<version>amd64.debSame desktop app, installed into the menu; needs no FUSE and takes WebKitGTK from the distribution. Not the server package — that one is libredb-studio<version><arch>.deb
Desktop app (Flatpak)flatpak --user remote-add --if-not-exists flatpark https://dl.flatpark.org/flatpark.flatpakrepo
flatpak --user install flatpark org.libredb.Studio
Sandboxed desktop app from the FlatPark remote — no filesystem access at all; databases are reached over TCP. Developer-approved listing (#241)

> Homebrew, deb/rpm, Snap, the Windows portable zip, winget/Chocolatey, the desktop AppImage and Debian package, and the npx launcher consume standalone artifacts attached to each GitHub release. Full per-channel guide — commands, configuration, systemd usage, and the Docker image tag model — in docs/DISTRIBUTION.md. Channel coverage scorecard (live / pending, by platform and category) — docs/CHANNELS.md.
### Quick Start (Docker)
Run LibreDB Studio with a single command — no clone, no install, no build:
docker run \
  --name libredb-studio \
  -p 3000:3000 \
  -e [email protected] \
  ghcr.io/libredb/libredb-studio:latest

> Registry: ghcr.io/libredb/libredb-studio is the primary image (no pull rate limits — preferred for Kubernetes/CI). The same image is also mirrored to Docker Hub as libredb/libredb-studio for convenience.
> Variants: every tag also ships on Alpine. :latest-alpine is the same product on a musl base with a much smaller OS attack surface, and :latest-alpine-slim is smaller still in exchange for the DuckDB driver. The default tag stays Debian and is the only one where Oracle Thick mode can be layered on — docs/DISTRIBUTION.md has the table.
> IPv6: the container picks its own bind address at startup and prefers ::, which serves IPv4 and IPv6 through one socket — so an IPv6-only host needs no flags. It falls back to 0.0.0.0 where the namespace has no usable IPv6, and logs which it chose. Add -e HOSTNAME=0.0.0.0 to pin it to IPv4 — details, and the Kubernetes equivalent, in docs/DISTRIBUTION.md.
Open http://localhost:3000. The command above sets no password, so the first start generates one and prints it to the container log with docker logs libredb-studio — sign in as [email protected] with the password it printed, or set ADMIN_PASSWORD yourself.
> Auth env vars (local provider): ADMIN_PASSWORD and JWT_SECRET are only required when AUTH_BOOTSTRAP=off; otherwise both are generated on first start (see Zero-config first run below). USER_EMAIL / USER_PASSWORD are optional; omit them to run admin-only (no default user password is ever assumed). ADMIN_EMAIL defaults to [email protected]. Using OIDC (NEXT_PUBLIC_AUTH_PROVIDER=oidc)? None of these are needed.
> Tip: Add -e LLM_PROVIDER=gemini -e LLM_API_KEY=your_key -e LLM_MODEL=gemini-2.5-flash to enable AI features.
### Zero-config first run
Starting the server without JWT_SECRET / ADMIN_PASSWORD works out of the box: the missing values are generated on first start, stored in <data dir>/auth-bootstrap.json (file mode 0600), and the admin password is printed once to the server log. Explicitly set environment variables always take precedence. Set AUTH_BOOTSTRAP=off to require explicit configuration instead (recommended for production deployments).
A JWT_SECRET you set yourself must be at least 32 characters. A shorter one is a hard error at startup: the server prints what is wrong and exits with code 1, instead of booting into a state where the health check reports healthy but every login returns 503. Unset the variable to let the first run generate a strong secret for you.
### Linux packages (.deb / .rpm)
Native packages for Debian/Ubuntu and RHEL/Fedora (amd64 and arm64) are attached to every GitHub release. They bundle the standalone server together with a private Node.js runtime (nothing else to install) and register a systemd service:
# Debian / Ubuntu
sudo dpkg -i libredb-studio_<version>_amd64.deb

# RHEL / Fedora / Rocky
sudo rpm -i libredb-studio-<version>.x86_64.rpm

# Start the service (first run prints the generated admin password to the journal)
sudo systemctl enable --now libredb-studio
journalctl -u libredb-studio

Configuration lives in /etc/libredb-studio/env (loaded by the unit; see the commented template installed there), state (SQLite storage and generated credentials) in /var/lib/libredb-studio. The libredb-studio command can also be run directly without systemd. Full details for this and every other channel: docs/DISTRIBUTION.md.
### Prerequisites - Bun (Recommended) or Node.js 24+ - A target database to query (PostgreSQL, MySQL, Oracle, SQL Server, SQLite, libSQL, DuckDB, MongoDB, Couchbase, ClickHouse, Apache Druid, Elasticsearch, OpenSearch, Apache Trino, Apache Cassandra, or Redis)
### Quick Start (Local) 1. Clone & Install
```bash
git clone https://github.com/libredb/libredb-studio.git
cd libredb-studio
bun install
```

    2. **Configure Environment**
  Create a `.env.local` file:
  ```env
  # Authentication (email/password)
  [email protected]
  [email protected]
  JWT_SECRET=your_32_character_random_string

  # Optional: OIDC Single Sign-On (Auth0, Keycloak, Okta, Azure AD, etc.)
  # NEXT_PUBLIC_AUTH_PROVIDER=oidc
  # OIDC_ISSUER=https://your-provider.com
  # OIDC_CLIENT_ID=your_client_id
  # OIDC_CLIENT_SECRET=your_client_secret

  # LLM Configuration
  LLM_PROVIDER=gemini # options: gemini, openai, ollama, custom
  LLM_API_KEY=your_api_key
  LLM_MODEL=gemini-2.5-flash
  LLM_API_URL=http://localhost:11434/v1 # optional for local LLMs (Ollama)
  ```
  1. Launch
```bash
bun dev
```
Open [http://localhost:3000](http://localhost:3000)
### Embedding in your own app (@libredb/studio)
Studio is published as an npm package as well as a server, so the editor can live inside your own product:
```bash npm i @libredb/studio ```
Adopt Studio's security headers from your own Next.js config. The @libredb/studio/security subpath publishes the header policy as pure data — securityHeaders() returns a plain Record<string, string>, and the module it comes from imports nothing, so it is safe to load from a next.config.ts where no path alias and no Studio runtime exist yet:
```ts // next.config.ts import { securityHeaders } from "@libredb/studio/security";
export default {
async headers() {
  return [
    {
      source: "/:path*",
      headers: Object.entries(securityHeaders()).map(([key, value]) => ({ key, value })),
    },
  ];
},
}; ```
Options: reportOnly emits Content-Security-Policy-Report-Only instead of the enforcing header; hsts: false disables HSTS (or an object customises it); allowEval adds 'unsafe-eval', which React's development build needs; monacoVsPath adds the origin serving Monaco's bundle when it is not same-origin; and extra merges your own sources per directive. studioCspDirectives() and HSTS_MAX_AGE_SECONDS are exported too, for a config that needs to compose the policy rather than send it.
Read the policy before you inherit it: the CSP permits inline scripts, because every document route is statically prerendered with nonce-less hydration scripts, so what it contains is where an injected script could send data, not whether one can run. That trade-off, and the two delivery paths a Next.js app has for these headers, are argued in docs/SECURITY.md.

Development Databases

Need databases to test with? We provide ready-to-use containers for all supported engines:
# Start every default-profile database (PostgreSQL, MySQL, MongoDB, SQL Server, Oracle, ...)
docker compose -f database-compose.yml up -d

# Or start a specific database
docker compose -f database-compose.yml up -d postgres
docker compose -f database-compose.yml up -d mssql
docker compose -f database-compose.yml up -d oracle

# Apache Druid: profile-gated, so a bare `up -d` does NOT start it. Druid is a distributed
# system with no single-container mode - five Druid processes plus ZooKeeper plus its own
# metadata database is the minimum that can answer a SQL query, so all seven services carry
# `profiles: [druid]` rather than doubling the default stack. Connect to the Router on 8888
# (or the Broker on 8082 - the same endpoint, no different configuration).
docker compose -f database-compose.yml --profile druid up -d

# Start PostgreSQL with sample e-commerce data
docker compose -f docker/postgres.yml up -d

# Stop (keeps data)
docker compose -f database-compose.yml down

# Stop and remove all data
docker compose -f database-compose.yml down -v

# The Druid containers need the profile flag here too - without it `down` leaves them running
docker compose -f database-compose.yml --profile druid down -v

Connection Details

DatabaseHostPortUserPasswordDatabase/Service
PostgreSQLlocalhost5432postgrespostgrespostgres
MySQLlocalhost3306rootrootmysql
SQL Serverlocalhost1433saPassword123!master
Oraclelocalhost1521systemPassword123!freepdb1
MongoDBlocalhost27017adminadmin
Apache Druidlocalhost8888 (Router) or 8082 (Broker)— (one catalog, always druid)
Apache Trinolocalhost8080tpch (a catalog; tpcds, memory, system and jmx are configured too)

PostgreSQL Sample Data

The docker/postgres.yml setup includes a pre-loaded e-commerce schema:
FeatureDescription
PostgreSQL 18Official image with pgstatstatements
pgstatstatementsPre-enabled for query monitoring
Sample SchemaE-commerce database (app schema)
Sample Data25 customers, 30 products, 100 orders
ViewsOrder summary, product sales, customer LTV

Sample tables: app.customers, app.products, app.orders, app.order_items, app.product_reviews, app.categories, app.coupons, app.audit_log
This setup is ideal for testing the Monitoring Dashboard features with real pg_stat_statements data.

Testing

LibreDB Studio has a comprehensive test suite: 549 test files and 17,692 tests across seven layers, plus 79 browser tests, with 100% line coverage enforced by CI (bun run coverage:check).

Quick Commands

# Every test file, each in its own bun process
bun run test

# Run by layer
bun run test:unit          # Pure function tests (328 files)
bun run test:api           # API route handler tests (35 files)
bun run test:integration   # Database provider tests (24 files)
bun run test:hooks         # React hook tests (21 files)
bun run test:security      # Security posture tests (21 files)
bun run test:evals         # LLM prompt evaluation tests (13 files)
bun run test:components    # Component tests (107 files: tests/components and tests/isolated)

# Any subset, and what the runner would run
bun tests/run-tests.ts tests/integration/db/duckdb-provider.test.ts
bun tests/run-tests.ts --list
bun tests/run-tests.ts --jobs=4          # bound the concurrency

# E2E tests (requires build)
bun run test:e2e           # Playwright browser tests (79 cases across chromium and webkit)

# Coverage report (lcov)
bun run test:coverage

Test Architecture

LayerDirectoryFilesTestsWhat it covers
Unittests/unit/3289,645Pure functions: SQL parser, connection strings, data masking, query limiter, schema diff, error classes, DB icons, showcase queries, and the packaging and chart manifests
APItests/api/35602Route handlers: auth, query, transaction, maintenance, AI endpoints, middleware
Integrationtests/integration/242,768Database providers: PG, MySQL, SQLite, MongoDB, Couchbase, Redis, Oracle, MSSQL, ClickHouse, Druid, Elasticsearch, OpenSearch, Trino
Hookstests/hooks/21566React hooks: auth, connections, tabs, query execution, transactions, inline editing, monitoring
Securitytests/security/21322The posture docs/SECURITY.md claims: route exposure, headers, audit channels, credential handling
Evalstests/evals/13198LLM prompt behaviour against recorded models
Componentstests/components/, tests/isolated/1073,376UI components with happy-dom: Studio, Sidebar, QueryEditor, ResultsGrid, Admin Dashboard, Charts, ERD
E2Ee2e/1879Full browser flows: login, connections, query execution, tabs, export, admin

The Files column was counted on 2026-09-15 with bun tests/run-tests.ts --list for the first seven rows and playwright test --list for the last. The Tests column comes from an earlier full run the same day, over the 542 files the tree held then, so the per-layer numbers are a little below the 17,692 above: they do not yet count the seven test files this branch and the merge from main add under tests/unit/, nor the cases this branch adds to the runner's own test files. The nineteenth spec in e2e/, base-path.spec.ts, is not in that 18: it needs its own server configuration and runs as bun run test:e2e:base-path.

Key Details

  • Test runner: tests/run-tests.ts over bun:test. It discovers every *.test.ts and *.test.tsx file under tests/ except tests/live/, so a new test file runs the moment it is added, and it runs each file in its own bun process, several at a time (one per CPU by default, --jobs=N to change it).
  • Why a process per file: bun's mock.module() is process-wide with no undo, and whole-module mocks are the standard pattern in tests/api/, so files that share a process contaminate each other. On Linux with 20 cores and bun 1.4.2, the suite took 211 seconds one file at a time, 61 seconds 4 at a time and 36 seconds 20 at a time, measured on 2026-09-15 over the 538 files the tree held then; docs/BACKLOG.md D86 carries the same three timings and the same basis.
  • One command everywhere: the runner is TypeScript rather than shell so that the command a contributor is told to run works on Linux, macOS and Windows from the platform's own shell. The bash scripts it replaced did not: one used mapfile, a bash 4 builtin that macOS's bash 3.2 does not have.
  • E2E: Playwright runs the full suite on Chromium and the security-headers spec on WebKit (webkit-security), against a production build (bun run build && bun start)
  • CI: GitHub Actions runs lint + typecheck + build, the required Unit & Integration Tests job (bun run test:coverage then bun run coverage:check) on ubuntu, a non-required Cross-platform Tests job running bun run test on windows-latest and macos-latest, E2E tests, and SonarCloud analysis
  • Coverage: bun run test:coverage is the same runner with --coverage, which writes one lcov per test file; scripts/merge-lcov.mjs merges them into coverage/lcov.info for the gate and for SonarCloud

Important: Always use bun run test, never bare bun test over a directory. bun test tests/api puts every file in one process, where one file's module mock becomes every file's. To run a single file, name it to the runner: bun tests/run-tests.ts tests/api/proxy.test.ts.

One-Click Deploy

Deploy your own instance of LibreDB Studio with a single click on DigitalOcean, Koyeb, Render, Railway, Sealos, CapRover, or Dokploy:
Deploy to Koyeb
Deploy to Render
Deploy on Railway
Deploy on Sealos
Deploy on DigitalOcean
Deploy on CapRover
Deploy on Fly.io
Deploy on Dokploy
DigitalOcean: the Marketplace listing creates a preconfigured Droplet. Unique admin credentials are generated on first boot; the welcome message (MOTD) tells you where to find them.
CapRover: open your CapRover dashboard → Apps → One-Click Apps/Databases, search for LibreDB Studio, and deploy.
Koyeb: set a strong JWT_SECRET (at least 32 characters — openssl rand -base64 32) and credentials before deploying (Koyeb cannot auto-generate secrets). The prefilled values are deliberately unusable: the secret is shorter than the 32-character minimum, so the app stops at boot and says so rather than running on a secret printed in this file. The button uses STORAGE_PROVIDER=local — connection metadata lives in the browser, which suits Koyeb's ephemeral filesystem. For persistence across redeploys, switch to STORAGE_PROVIDER=postgres and point STORAGE_POSTGRES_URL at a Koyeb managed Postgres or Neon database. The button also fills in LLM_PROVIDER/LLM_MODEL/LLM_API_KEY, but Agent mode needs a server-held connection, so its Start button stays disabled until STORAGE_PROVIDER is sqlite or postgres (see docs/AGENT.md). See deploy/koyeb/.
Fly.io: the repo ships a ready fly.toml — full steps (app name, volume, secrets) in docs/FLY.md.
Cosmos: install in one click from the Cosmos Marketplace — search for LibreDB Studio. Cosmos auto-generates secrets, provisions a persistent SQLite volume, and serves the app behind its SmartShield reverse proxy. See deploy/cosmos/.
Dokploy: install in one click from the Dokploy template catalog — in your Dokploy dashboard, Create Service → Template, search for LibreDB Studio, and deploy. Dokploy auto-generates ADMIN_PASSWORD, USER_PASSWORD, and JWT_SECRET, and persists connections on a SQLite volume behind Traefik. See deploy/dokploy/.

Environment Variables

VariableRequiredDescription
ADMINEMAILAdmin email (default: [email protected])
ADMINPASSWORD✅(autogenerated)Admin password; auto-generated on first run unless AUTHBOOTSTRAP=off
USEREMAILOptional user account email (default: [email protected])
USERPASSWORDOptional; the lower-privilege user account exists only when set
JWTSECRET✅(autogenerated)JWT secret (min 32 chars); auto-generated on first run unless AUTHBOOTSTRAP=off. A shorter value is fatal: the server refuses to start rather than serve a deployment where every login fails
AUTHBOOTSTRAPoff disables zero-config generation (strict mode; recommended for production)
AUTHCOOKIESECUREfalse drops the Secure flag from auth cookies — needed only when the browser reaches the app over plain HTTP (LAN/home server); not for TLS terminated at an ingress
NEXTPUBLICAUTHPROVIDERlocal (default) or oidc for SSO
OIDCISSUEROIDC issuer URL (required when oidc)
OIDCCLIENTIDOIDC client ID (required when oidc)
OIDCCLIENTSECRETOIDC client secret (required when oidc)
OIDCADMINROLESComma-separated admin role values (default: admin)
OIDCROLECLAIMClaim path for role (e.g. realmaccess.roles)
OIDCSCOPEOIDC scope (default: openid profile email)
LLMPROVIDERAI: gemini, openai, ollama, custom (self-hosted OpenAI-compatible endpoint)
LLMAPIKEYAPI key for AI features
LLMMODELModel name (e.g., gemini-2.5-flash)
LLMAPIURLAPI URL for ollama and custom; required for custom, defaults to http://localhost:11434/v1 for ollama
STORAGEPROVIDERStorage provider: local (default), sqlite, or postgres
STORAGESQLITEPATHSQLite file path (e.g. /app/data/libredb-storage.db)
STORAGEPOSTGRESURLPostgreSQL connection URL (required when STORAGEPROVIDER=postgres)
SEEDCONFIGPATHPath to seed connections YAML config (see Seed Connections)
SEEDCACHETTLMSSeed config cache TTL in ms (default: 60000)

Tip: Copy .env.example to .env.local for local development.

Deployment (DevOps)

For a reverse-proxy path such as /tools/libredb, build with BASE_PATH and follow the subpath deployment guide. Prebuilt images use the root path.
Maintainers: every distribution channel is inventoried in distribution/channels.yaml; bun run distribution:check reports version drift across all of them (see docs/DISTRIBUTION.md).

Koyeb

  1. Use the Deploy to Koyeb button under One-Click Deploy to run the prebuilt ghcr.io/libredb/libredb-studio:latest image.
  2. Set a strong JWT_SECRET (32+ characters) in the deploy form before launching. Koyeb cannot auto-generate secrets, and the prefilled one is shorter than the 32-character minimum on purpose, so a deployment left as it stands stops at boot and says why. No password is prefilled: leave ADMIN_PASSWORD unset and the app generates one on first run and prints it to the Koyeb runtime log, or set your own. USER_PASSWORD is not generated — without it the lower-privilege account does not exist at all, which is the safer default for a public URL.
  3. For connections to survive redeploys, set STORAGE_PROVIDER=postgres and STORAGE_POSTGRES_URL to a Koyeb managed Postgres or Neon connection string. The button defaults to STORAGE_PROVIDER=local, which keeps connection metadata in the browser.

See deploy/koyeb/ for the complete setup and storage options.

Railway

LibreDB Studio is available as a one-click Railway template. See deploy/railway/ for the template definition, install instructions, and the publish checklist. The template runs the prebuilt ghcr.io/libredb/libredb-studio image with SQLite persistence on a Railway volume. Note: Docker-image templates require a manual version bump on each release (same as CapRover).

CapRover

LibreDB Studio is published in the official CapRover One-Click Apps catalog:
  1. Open your CapRover dashboardApps → One-Click Apps/Databases
  2. Search for LibreDB Studio
  3. Fill in the variables (admin/user credentials, JWT_SECRET, optional AI/storage settings)
  4. Deploy!

The app runs the prebuilt ghcr.io/libredb/libredb-studio image. As with Railway, Docker-image templates require a manual version bump on each release.

Kubero

LibreDB Studio is listed in the official Kubero template catalog (a self-hosted "Heroku alternative for Kubernetes"). From your Kubero dashboard, browse Templates, search LibreDB Studio, fill in the credentials / JWT_SECRET, and deploy. The template runs the prebuilt ghcr.io/libredb/libredb-studio image with SQLite persistence on a 5Gi volume at /app/data. See deploy/kubero/ for install and post-install details. As with Railway and CapRover, Docker-image templates require a manual version bump on each release.

Cosmos

LibreDB Studio is listed in the official Cosmos servapp marketplace (Cosmos is a self-hosted server manager and secure reverse proxy). From your Cosmos dashboard, open Marketplace, search LibreDB Studio, and install. Cosmos auto-generates the credentials and JWT_SECRET, provisions a persistent SQLite volume at /app/data, and serves the app behind a SmartShield-protected route. See deploy/cosmos/ for install and post-install details. As with Railway, CapRover, and Kubero, Docker-image templates require a manual version bump on each release.

Render (Recommended for cloud deployment)

LibreDB Studio includes a render.yaml Blueprint for one-click deployment:
  1. Fork this repository
  2. Connect to Render: dashboard.render.com → New → Blueprint
  3. Select your forked repo and Render will auto-detect render.yaml
  4. Set Environment Variables in Render Dashboard:
  5. Deploy!

Docker Compose (Self-Hosted)

Use the ready-to-use docker-compose.example.yml — it pulls the published image (ghcr.io/libredb/libredb-studio:latest), so no source build is needed. It documents every supported environment variable (auth, OIDC, storage, LLM, seed connections), with the less-common ones commented out.
# 1. Copy the ready-to-use compose file
cp docker-compose.example.yml docker-compose.yml

# 2. Create your .env (set at least JWT_SECRET / ADMIN_PASSWORD / USER_PASSWORD)
cp .env.example .env

# 3. Start
docker compose up -d   # → http://localhost:3000

This file is platform-neutral and works with PaaS tools that consume a plain docker-compose.yml (Dokploy, Coolify, Portainer, etc.) — point them at the file and set the secrets as environment variables.
The repository's default docker-compose.yml builds the image from source (build: .) and is intended for local development.

Kubernetes (Helm Chart)

helm repo add libredb https://libredb.org/libredb-studio/
helm install libredb libredb/libredb-studio

# Retrieve the generated admin credentials from the pod log
kubectl logs deployment/libredb-libredb-studio | grep -A 4 "generated admin credentials"

Or via OCI registry:
helm install libredb oci://ghcr.io/libredb/charts/libredb-studio

For production, provide your own secrets instead of relying on generated ones:
helm install libredb libredb/libredb-studio \
  --set secrets.jwtSecret=$(openssl rand -base64 32) \
  --set secrets.adminPassword=MyAdmin123

Features: PostgreSQL subchart, Ingress/TLS, HPA, PDB, NetworkPolicy, ExternalSecrets support. See charts/libredb-studio/README.md for full documentation.

Seed Connections (Pre-Configured Databases)

Pre-configure database connections via a YAML config file so users see them immediately after login. Ideal for Platform/SaaS deployments where admins provision databases for teams.
Features:
  • Role-based access control (admin, user, * wildcard)
  • Hybrid model: managed: true (read-only, admin-controlled) or managed: false (editable copy for user)
  • Credentials injected via ${ENV_VAR} syntax — never stored in config file
  • Hot-reload: config changes apply within 60s without restart
  • Works with Docker, docker-compose, and Kubernetes (Helm)

1. Create a config file (seed-connections.yaml):
version: "1"

defaults:
  managed: true
  environment: production

connections:
  - id: "prod-analytics"
    name: "Production Analytics"
    type: postgres
    host: analytics-db.internal
    port: 5432
    database: analytics
    user: "readonly_user"
    password: "${ANALYTICS_DB_PASSWORD}"
    roles: ["admin"]
    color: "#10B981"

  - id: "dev-sandbox"
    name: "Dev Sandbox"
    type: mysql
    host: dev-mysql.internal
    port: 3306
    database: sandbox
    user: "dev_user"
    password: "${DEV_DB_PASSWORD}"
    roles: ["*"]
    managed: false

2. Mount and configure:
Docker
docker run -v ./seed-connections.yaml:/app/config/seed-connections.yaml:ro \
  -e SEED_CONFIG_PATH=/app/config/seed-connections.yaml \
  -e ANALYTICS_DB_PASSWORD=secret \
  -e DEV_DB_PASSWORD=devsecret \
  ghcr.io/libredb/libredb-studio:latest

Docker Compose
services:
  app:
    image: ghcr.io/libredb/libredb-studio:latest
    volumes:
      - ./seed-connections.yaml:/app/config/seed-connections.yaml:ro
    environment:
      SEED_CONFIG_PATH: /app/config/seed-connections.yaml
      ANALYTICS_DB_PASSWORD: ${ANALYTICS_DB_PASSWORD}
      DEV_DB_PASSWORD: ${DEV_DB_PASSWORD}

Kubernetes (Helm)
# values.yaml
seedConnections:
  enabled: true
  config:
    version: "1"
    connections:
      - id: "prod-analytics"
        name: "Production Analytics"
        type: postgres
        host: analytics-db.internal
        password: "${ANALYTICS_DB_PASSWORD}"
        roles: ["admin"]

# Credentials via K8s Secret:
extraEnvFrom:
  - secretRef:
      name: seed-db-credentials

Config Reference:
FieldRequiredDescription
versionYesMust be "1"
defaultsNoDefault values merged into all connections
connections.idYesUnique slug (a-z0-9-+, max 64 chars)
connections.nameYesDisplay name in UI
connections.typeYespostgres, mysql, sqlite, mongodb, redis, oracle, mssql, libredb, couchbase, clickhouse, druid, elasticsearch, opensearch, trino
connections.rolesYes"" (everyone), "admin", "user", or "admin", "user"
connections.managedNotrue = read-only (default), false = editable copy for user
connections.passwordNoUse ${ENVVAR} syntax for secrets
connections.environmentNoproduction, staging, development, local, other
connections.groupNoGroup label in sidebar
connections.colorNoHex color for badge (e.g., #10B981)

Environment Variables:
VariableDefaultDescription
SEEDCONFIGPATH/app/config/seed-connections.yamlPath to config file
SEEDCACHETTLMS60000Cache TTL in ms (hot-reload interval)

One-Command Vault Demo

docker-compose.vault-demo.yml starts Studio, PostgreSQL and a dev-mode HashiCorp Vault, plus a one-shot init container that writes the database password into Vault and the seed file into the volume Studio mounts. It pulls the published image, so there's nothing to build, and the connection it defines takes its password from Vault through the reference ${vault:secret/data/prod/postgres#password} instead of from an environment variable.
docker compose -f docker-compose.vault-demo.yml up

Open http://localhost:3000 and log in with the admin credentials the first run prints to the Studio log, same as the Quick Start. The sidebar has a Postgres (password from Vault) connection — open it and run any statement, and it connects with the password Vault holds. To watch a rotation, change the password in Vault and in PostgreSQL, wait out the 10-second cache the file sets, and open the connection again: it authenticates with the new value, with no container restarted.
The Vault in that file is dev mode — in-memory, root token, no TLS, no policies — so it's for demonstration only. The reference scheme, the VAULT_* variables, the rotation window and both rotation commands are in docs/SEED_CONNECTIONS.md; a real deployment starts from HashiCorp's production hardening guide.

Roadmap

  • x Phase 1: Monaco SQL IDE & Multi-Tab Support.
  • x Phase 2: Multi-Model AI (Gemini, OpenAI, Ollama, Custom) Integration.
  • x Phase 3: Pro Data Grid & Virtualization.
  • x Phase 4: Multi-Database Support (PostgreSQL, MySQL, SQLite, MongoDB, Redis).
  • x Phase 5: Interactive ER Diagrams (Visual Schema Graph).
  • x Phase 6: Enterprise Foundation (Connection Testing, SSL/TLS, SSH Tunnel, Transaction Control, Query Cancellation).
  • x Phase 7: AI Intelligence (Query Safety Analysis, AI Query Explainer, AI-generated schema descriptions).
  • x Phase 8: Analyst & Developer Tools (Data Profiler, Code Generator, Test Data Generator, Pivot Table, Column Filtering, Database Docs).
  • x Phase 9: Display Masking — Preview (column-name pattern matching, configurable rules, RBAC UI controls, client-side export/clipboard masking).
  • x Phase 10: Advanced ERD (Real FK Edges, ELK.js Auto-Layout, MiniMap, PNG/SVG Export, Compact Mode, Table Search).
  • x Phase 11: Schema Diff & Migration (Snapshot Timeline, Cross-Connection Diff, Migration SQL Generation for PostgreSQL, MySQL, SQLite, Oracle, and SQL Server, plus ClickHouse column modifications).
  • x Phase 12: Advanced Charting (Scatter, Histogram, Stacked Charts, Aggregation, Date Grouping, Chart Save/Load, Chart Dashboard).
  • x Phase 13: Monitoring Enhancement (Time-Series Trends, Threshold Alerting, Connection Pool Stats, Configurable Polling).
  • x Phase 14: Enterprise Database Support (Oracle Database via oracledb Thin mode, Microsoft SQL Server via mssql/tedious).
  • x Phase 15: SSO Integration — Vendor-agnostic OIDC authentication (Auth0, Keycloak, Okta, Azure AD, Zitadel) with PKCE, role mapping, and provider logout.
  • Phase 16: DBA & Monitoring (Lock Dependency Graph, Vacuum Scheduler, Prometheus Export).
  • Phase 17: Enterprise Collaboration (User Identity, Shared Workspaces, SAML 2.0).
  • Phase 18: Server-Enforced Data Masking (SQL output-lineage, deployment-global policy, fail-closed API masking, alias/aggregate coverage).
  • x Phase 19: Driver-Free Providers — Couchbase (SQL++ over the Query REST API), the first provider that adds no runtime dependency. Pattern documented in Adding a Provider.
  • x Phase 20: Analytics Databases — ClickHouse (#264) and Apache Druid (#265), both driver-free over HTTP. Druid is read-only by nature — no UPDATE, no DELETE, no CREATE TABLE — so it also demonstrates a provider that reports absent capabilities honestly instead of offering controls that can only fail.
  • x Phase 21: Federated Query — Apache Trino (#424, Phase 2), driver-free over Trino's own client protocol. The product question that held it up is answered: a connection pins one catalog, exactly as a PostgreSQL connection pins one database, and the tree stays two levels — fanning information_schema across every catalog is unbounded, since jmx.current alone publishes one table per MBean. Cross-catalog queries still work in the editor by qualifying names in full. PrestoDB is a separate future type-id; the transport already builds its headers from a dialect prefix so that is a descriptor, not a rewrite.

Community & Quality

ResourceDescription
DeepWikiAI-powered documentation — always up-to-date with the codebase
SonarCloudCode quality, security analysis, and technical debt tracking
API DocsComplete REST API reference
Agent GuideUsing the agent: a run, the three workflows, what "answered" means, the budget meter, and the Ollama path
Agent Data FlowWhat leaves the machine, when, and to which model provider — written from call sites
Local modelsWhich local model can actually drive an agent run, measured across three workflows, one page per model
Agent RuntimeAgent behaviour, bounds, deployment and known limitations
OIDC SSOSSO setup (Auth0, Keycloak, Okta, Azure AD, Zitadel, Google) + subsystem internals & security model
Two-Factor AuthTOTP on the local provider — generating a secret, enrolling an app, Docker/Helm wiring, and what it does not cover
Theming GuideCSS theming, dark mode, and styling customization
Login PageLogin page layout, OIDC/local modes, and design system
Editor DocsSQL editor internals — completion, performance, query optimization
ArchitectureSystem architecture and design patterns
Adding a ProviderStep-by-step guide to adding a database, and how to tell whether it needs a driver at all
BacklogKnown defects and deferred work that is not yet filed as an issue

Cross-browser testing

The product is a browser application, so a browser bug is a product bug. CI runs the full Playwright suite on desktop Chromium and the security-headers spec on WebKit (webkit-security). Beyond that one WebKit spec, Safari and older WebKit regressions, mobile layout, and the WebKitGTK engine behind the Linux desktop build need real devices. This project is tested with BrowserStack.

Support

libredb-studio is free and open source. If it helps you or your team, consider sponsoring the project — your support funds maintenance, bug fixes, new database providers, and the ongoing development of the open-source edition.
Sponsor

Sponsors

Be the first to sponsor libredb-studio!

Supporters

Distinct from the sponsors above: these are open-source programmes that cover a running cost of the project. A place here cannot be bought, and nothing here is an endorsement of libredb-studio by the company named. The full list, what each one covers and what attribution is owed in return are at libredb.org/supporters.
Docker-Sponsored Open Source programme behind the libredb namespace on Docker Hub, which removes pull rate limits for everyone pulling the public image. The canonical image is still GHCR; this is what keeps the Hub mirror usable without an account. Since 2026-09-01.
Open Source programme behind the cross-browser testing that runs the full Playwright suite on desktop Chromium and the security-headers spec on WebKit (webkit-security). Beyond that one WebKit spec, Safari and older WebKit regressions, mobile layout, and the WebKitGTK engine behind the Linux desktop build need real devices. Since 2026-08-31.
plan behind the private network maintainers use to reach the database probe hosts, so testing against real engines does not mean exposing database ports to the internet. Since 2026-08-30.

Contributing

We welcome contributions from the community! Whether it's a bug fix, a new feature, or documentation improvements:
  1. Fork the Project.
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature).
  3. Commit your Changes (git commit -m 'Add some AmazingFeature').
  4. Push to the Branch (git push origin feature/AmazingFeature).
  5. Open a Pull Request.

Every change here lands with its tests in the same pull request, under a hard 100% line-coverage gate. Clearing that bar is worth something, so the people who have are named in CONTRIBUTORS.md with a link to the change they made. Nothing on that page is counted — no merge totals, no line counts — and CONTRIBUTING.md says why. Start with a good first issue: each one states what "done" looks like as a command you can run yourself.

License

Distributed under the MIT License. See LICENSE for more information. One direct dependency, elkjs, is under the reciprocal EPL-2.0; see docs/THIRD_PARTY_LICENSES.md.

Built for DBAs and Developers.

Serve LibreDB Studio on your own domain behind Caddy, Nginx or Traefik. Fill in your domain and copy the result. It's a starting point, some apps need their own base URL or extra headers set too.

Proxying libredb-studio.example.com to http://libredb-studio:3000

Add this to your Caddyfile

libredb-studio.example.com {
	reverse_proxy http://libredb-studio:3000
}

Check the logs first

Nine times out of ten the logs tell you exactly what went wrong.

  • In Portainer, go to Containers, click the container, then Logs. Or run docker logs libredb-studio
  • Exit codes help too: 137 means killed, usually out of memory. 126 or 127 means the command inside the image is broken.

Port already in use

If deployment fails with "Bind for 0.0.0.0:3000 failed: port is already allocated", something else on your server is using that port.

  • Find what's using it: sudo ss -tlnp | grep :3000
  • Stop the other service, or pick a different host port. In 3000:3000 only the left number is yours to change, the right one belongs to the app.

Running but the page won't load

The container is up but nothing appears in your browser.

  • Use your server's real IP: http://your-server-ip:3000. The 0.0.0.0 link Portainer shows isn't a real address.
  • Give it a minute after first deploy, libredb-studio can take a while to initialise.
  • Make sure your firewall allows the port, e.g. sudo ufw allow 3000

Image won't pull

Test the pull directly on the host: docker pull ghcr.io/libredb/libredb-studio:latest

  • "manifest unknown" means the tag no longer exists. This template uses latest, so try pinning a specific version instead.
  • "toomanyrequests" is the Docker Hub rate limit. Log in with docker login to raise it.
  • "no space left on device" means a full disk. Reclaim space with docker system prune

"exec format error"

This means the image was built for a different CPU architecture than your server.

  • This image supports: amd64, arm64
  • Check yours with uname -m: x86_64 is amd64, aarch64 is arm64. Raspberry Pi and other ARM boards are the usual culprits.

Container keeps restarting

The unless-stopped restart policy relaunches the app after every crash, so the real error can scroll past.

  • Check the logs right after a restart, the last few lines before it died are the useful ones.
  • Get the exit code with docker inspect libredb-studio --format '{{.State.ExitCode}}'
  • Still stuck? Redeploy once with the restart policy set to no so the failure stays visible.

Raise an issue

Found something which isn't working as it should? Here's how to report it.

A single container

LibreDB Studio runs as one container, the simplest kind of app here. Just the one image to pull and nothing else wired up alongside it.

The app image

An image is the app packed up ready to go, everything LibreDB Studio needs bundled into one download. This template pulls ghcr.io/libredb/libredb-studio:latest, which Docker fetches once (about 198 MB) and then starts your own copy from.

Where the image comes from

Docker pulls its images from registries, public libraries of ready-built apps. LibreDB Studio's comes from the GitHub Container Registry, published by libredb.

Version tags

The bit after the colon in the image name is the version tag. Here it's latest, which always points at the newest build, so a redeploy can bump you to a newer release without you asking. Pin a specific tag if you would rather stay on one version.

Which machines it runs on

Every image is built for particular CPU types. This one ships for amd64, arm64, so it runs on both regular x86 servers and ARM boards like a Raspberry Pi.

Ports

A port is the door the app answers on. A mapping like 3000:3000 means it's reachable on port 3000 of your server, where the left number is yours to change and the right one belongs to the app. Once it's running, open http://your-server-ip:3000 in a browser. It opens:

  • 3000:3000, likely the web interface

Volumes

A volume is where LibreDB Studio keeps its files so they survive an update or a restart. Without one, anything it saves would sit inside the container and vanish the moment it's recreated. This template mounts:

  • /app/data as a volume Docker manages for you

Restart policy

The restart policy here is unless-stopped, so Docker restarts LibreDB Studio after a crash or reboot, but leaves it off when you stop it on purpose. You can change this on the deploy screen. The choices are no (never restart), on-failure (only after a crash), unless-stopped (restart unless you stop it), and always (bring it back no matter what).

Networking

Nothing custom is set, so LibreDB Studio sits on Docker's default bridge network: its own private space that reaches the outside world only through the ports it publishes.

Container name

Once it's deployed, Portainer names the container libredb-studio. That's what you'll spot in the containers list and use in commands like docker logs libredb-studio.

Platform

The platform is linux, the kind of system the container is built to run on. Docker and Portainer handle this on a normal Linux server.

Open source license

LibreDB Studio is open source, released under the MIT license. In plain terms the code is out in the open, so you're free to run it and change it to fit what you need.

Portainer app templates

Zooming out, this whole page comes from a Portainer app template: a short recipe telling Portainer how to set LibreDB Studio up. Add the template list to Portainer once, then deploying LibreDB Studio is a click rather than a wall of config.