Repository navigation
0.18.0
LibreDB Studio 0.18.0 adds eight connection types for seven engines: etcd, IBM Db2, Neo4j with a Graph tab for Cypher results, Qdrant, Milvus, InfluxDB as two connection types, and Oxia.
It now connects on its own to the databases CapRover runs and to the managed database DigitalOcean creates with the 1-Click Droplet, and on sqlite or postgres storage local sign-in gains passkeys and any number of accounts.
It also fixes a session bypass in OIDC sign-in that affects every deployment from 0.7.0 through 0.17.0 with OIDC_ISSUER, OIDC_CLIENT_ID and OIDC_CLIENT_SECRET set, whatever NEXT_PUBLIC_AUTH_PROVIDER says, so operators of such a deployment should upgrade.
Two more fixes narrow what standard users reach on the server: their DuckDB connections run with file and network access off, and SQLite connections open only for admins (see Upgrading).
The rest is a long run of correctness fixes, most of them measured live against the engine they touch: dates, numbers and binary values shown as the engine stores them, SQL INSERT exports that replay, and maintenance, cancel and SANDBOX that say only what actually happened.
Key-value and coordination stores: etcd and Oxia
etcd connects read-write over etcd's gRPC API (#1228). The editor runs one etcdctl command at a time: get, put, del, txn, leases, a bounded watch, member list, endpoint status and health, alarm list, auth status, users and roles. The tree lists key-prefix groups, members, leases, users and roles. A key's value is edited from the Source tab as one Txn guarded by its mod_revision, so a concurrent change makes the edit fail instead of overwriting it. Compaction, defragmentation and alarm disarm are admin-only cards on Admin > Operations, confirmed by typing the connection's name.
It is Kubernetes-aware. Every write to a Kubernetes key prefix or to kube-apiserver's compact_rev_key is refused on the server, and Kubernetes protobuf, encrypted values and secrets are withheld everywhere. A seed connection can be declared readOnly: true. etcd has no agent execution mode and no MCP. Measured on etcd 3.7.2 as a single member, a cluster, and with client certificate and password auth; 3.6.0 and 3.6.6 for the auth behaviour.
Oxia connects read-only over its gRPC client API (#1310): look up, list and range-scan keys with oxia client commands, browse shards, and walk every key in the Keys panel. The namespace is the connection's Database field, Token is a bearer token, and a cluster lists its data servers in a new Data servers field. Studio dials a shard leader only when it is the address it connected to or a listed data server, sends the token nowhere else, refuses a token without TLS to a non-local host unless allowInsecureAuth is set, and sends no write call at all. Measured on Oxia 0.16.10 and 0.17.1.
IBM Db2 LUW
Db2 for Linux, UNIX and Windows connects as db2 over the db2-node driver, a native client that needs no IBM client install (#1238, closes #786; moved to db2-node 1.0.24 in #1303 and 1.0.25 in #1353). It takes host, port, database, user and password or a pasted db2:// URL, supports TLS verify-full and verify-ca, and refuses to send a password without TLS unless the connection sets allowInsecureAuth. The tree shows schemas with tables, views, MQTs, aliases, sequences, modules, procedures, functions and triggers; queries page on the server; inline row edit and import into existing tables work; and the operations page offers RUNSTATS and REORG on tables. Agent and MCP take the Oracle posture: plan mode and inspect_schema only. Measured on Db2 12.1.0.0 and 11.5.9.0, with and without TLS.
Limits in this version: no Db2 for z/OS or IBM i, no EXPLAIN, transactions, cancel, Create Table or object edit. Because db2-node 1.0.25 silently writes nothing to a CLOB, DBCLOB or BLOB column declared 32768 bytes or more, and a result does not carry the declared length, the grid opens no inline editor on any Db2 CLOB, DBCLOB or BLOB cell and says why (#1353).
Neo4j and the Graph tab
Neo4j 5.26 LTS connects read-only as neo4j over bolt, bolt+s and bolt+ssc, with SSH tunnel support (#1239). One database per connection: the tree shows node labels and relationship types with their properties, indexes and constraints, and the editor runs read-only Cypher with its own language and completion, plan mode and the MCP metadata tools. Every write is refused before it is sent, by a token-level read policy, a server EXPLAIN gate and a READ session. LOAD CSV, APOC, GDS and parameters are refused, and agent execution and MCP run_read_query do not serve Neo4j. There is no neo4j:// routing and no Aura.
A Cypher result that holds nodes, relationships or paths gets a Graph tab next to Results, drawn with Cytoscape.js from only what the statement returned, with no extra query (#1289). Nodes are deduplicated by elementId and coloured per label with a legend; clicking one opens an inspector, and the tab has fit, zoom, re-layout, PNG and JSON export and keyboard controls. At most 300 nodes are drawn, with a notice when a result holds more. Masking follows the grid in captions, the inspector and both exports.
Vector databases: Qdrant and Milvus
Both are new in a vector family that shares a console grammar, an in-flight limiter and a per-type statement size bound (#1247), and the results grid shows a declared vector column as its first 8 elements and its size, such as 768 dims, with the whole value in row detail and Copy Cell (#1248).
Qdrant connects read-only as qdrant over its REST API (#1270). Browse collections with their vectors, payload indexes and a sampled view of payload keys, and run Qdrant's own METHOD /path read requests with one JSON body from a closed console: point reads, scroll, count, facet, queries, batches and grouped queries over dense, sparse and multivector data. Studio refuses every inference input except the local BM25 model, sends an API key without TLS only to a loopback address or through an SSH tunnel, warns about a JWT with no expiry or with manage access, and shows MCP clients only schema and payload-index names. An http(s):// address pasted into the Host box fills Host, Port and SSL Mode (#1244, #1281). Measured on Qdrant 1.19.1.
Milvus connects as milvus, carried over gRPC by Studio's own client (#1283). Browse databases and collections with fields, partitions, indexes and load state, and run reads, exact counts and searches over every vector type, BM25 and hybrid included, from a console that takes Milvus's own POST /v2/vectordb/<route> requests. Studio writes no data; an admin can Load or Release a collection after a preview and a typed name, and the action is audited. Requests that would make the server call another service are refused, a password goes without TLS only to loopback or through an SSH tunnel, and the default root password is warned about. An empty list result says it holds only what this Milvus user has a privilege on (#1287). Measured on Milvus 3.0.2.
Columns inferred from sampled data are marked sampled in the tree and withheld from MCP inspect_schema, agent grounding and the AI panels (#1247).
InfluxDB, as two connection types
InfluxDB reads as two read-only connection types (#1309). influxdb, "InfluxDB (InfluxQL)", reads 1.x, 2.x through its v1 API, and 3.x over POST /query. influxdb3, "InfluxDB 3 (SQL)", reads one 3.x database over POST /api/v3/query_sql. Flux is not offered. Each type refuses anything but a read before any request is sent, one answer is capped at 16 MiB, and each type runs two calls at a time. Measured on InfluxDB 1.13.1, 2.9.1 and 3.12.0.
Platform integrations: CapRover and DigitalOcean
CapRover. A new opt-in one-click template, libredb-studio-autoconnect, adds a discovery companion that reads the Docker socket and exports the databases CapRover runs (#1502). Studio lists them as connections for admins only, never returns their passwords, follows databases added or removed later, and shows the discovery status on an admin Overview card. Studio reads the export through SEED_DISCOVERY_PATH and withdraws the discovered connections once the last scan is older than SEED_DISCOVERY_MAX_AGE_MS; the companion's DISCOVERY_* settings are in .env.example and docs/SEED_CONNECTIONS.md. The plain CapRover template stays socket-free. A standard user cannot read the export file through a DuckDB connection (#1519, see Security fixes). Measured on CapRover 1.15.4 with five official database apps. The template states its app-name limit, 39 characters starting with a letter, and has CapRover create the app that holds the Docker socket last, so an install that stops on a name CapRover refuses never leaves that app running on its own (#1528). The plain template's install text was also corrected: it no longer tells operators to set STORAGE_ENCRYPTION_KEY before rotating JWT_SECRET, which loses saved connection passwords (#1203).
DigitalOcean. When a managed PostgreSQL or MySQL database is added while creating the LibreDB Studio 1-Click Droplet, first boot turns its credentials into one managed seed connection, admin role only, with TLS required. The login message says whether the database was added, and why not when it was not (#1378).
Launch sign-in for platforms that host Studio
A platform that runs Studio for its users can now sign them in with one click: it signs a token valid for at most a minute, opens /launch#token=<token>, and Studio exchanges it for its ordinary session cookie, on a seeded connection when the token names one (#1516). With sqlite or postgres storage the first launch creates an account bound to the person's platform identity, with no password and the role the token names, and a later launch reaches only that account. A launch never signs in to an account that has a password, an authenticator or a passkey, never to the ADMIN_EMAIL address, and never replaces another person's session; in a browser with no Studio session it names the account and waits for a Continue as click. It stays off until LAUNCH_TOKEN_SECRET is set with LAUNCH_TOKEN_AUDIENCE and LAUNCH_TOKEN_ISSUER, and it is not available under OIDC. The guide, with the token format and every answer of POST /api/auth/launch, is docs/LAUNCH.md.
Three settings serve the same platforms and work on their own as well. ALLOW_CUSTOM_CONNECTIONS=false limits every user to the seed connections: routes that build a provider refuse any other connection with 403 CUSTOM_CONNECTIONS_DISABLED, and the editor hides New connection, Edit and Duplicate; it is on when unset, and a value it does not recognise switches it off and logs an error. SEED_LITERAL_VALUES=true reads every seed value as written, with no ${...} or Vault resolution, for a seed file written from data the platform's users control. And a /?connection=<id> link opens the editor on that connection, also after signing in.
Sign-in: passkeys and more than two local accounts
Any number of local accounts. With STORAGE_PROVIDER=sqlite or postgres, local email and password accounts live in an accounts table, so a team can have any number of admins and users, managed under Admin > Accounts: create, change role, disable, delete and set a password (#1122, closes #784). The last enabled admin cannot be removed. Sessions and MCP tokens end at the next request when an account is disabled, deleted, demoted or has its password reset, and every account can set up its own TOTP authenticator. STORAGE_PROVIDER=local and OIDC mode are unchanged. See Upgrading for how ADMIN_* and USER_* behave now.
Passkeys. On the same storage, local accounts can register passkeys and sign in with one, with no email, password or code (#1195, closes #785). User verification is required, so a passkey sign-in counts as a full multi-factor sign-in. Passkeys stay off until PASSKEY_ORIGIN names the address users open Studio at (chart: config.passkeyOrigin); browsers offer them only over https or on http://localhost. Failed passkey sign-ins have a rate-limit budget of their own, RATE_LIMIT_PASSKEY_MAX and RATE_LIMIT_PASSKEY_WINDOW_SEC, so passkey retries never lock password sign-in. Admins see a passkey count per account and can remove them behind a typed confirmation. The authenticator page is renamed Sign-in security.
An ended session. When the session cookie is missing or no longer verifies, API routes answer 401 JSON with code AUTH_REQUIRED instead of a redirect, so the editor no longer shows Unexpected token '<' ... is not valid JSON. The standalone app sends the tab to /login?next=<page> and returns there after sign-in by password, passkey or OIDC (#1484, closes #1420).
Dates, numbers and binary values as the engine stores them
Several engines handed the grid a JavaScript Date or a rounded number, so values shifted with the Studio server's time zone or lost digits. They now arrive as the engine's own text:
- PostgreSQL
dateandtimestampand their arrays no longer shift with the server's time zone;date '2026-09-01'showed as the previous day under Europe/Istanbul.timestamptzstays an instant (#1134).interval,pointandcircleshow as psql does, and a top-level jsonnullshows asnulltext (#1503, closes #1432). - MySQL-wire
DATE,DATETIMEandTIMESTAMPshow as the server's text with microseconds and zero dates kept, and inline edits of date cells are accepted (#1505, closes #1388). - SQL Server
time,dateanddatetime2keep all seven fraction digits instead of invented UTC instants (#1178, closes #1132). - Oracle
DATEandTIMESTAMPshow the stored wall clock, and the SQL INSERT export writes them back throughTO_DATEandTO_TIMESTAMP(#1225, closes #1131). - Integers past 2^53 and wide decimals keep their exact digits on ClickHouse, Redis, Couchbase, Elasticsearch, OpenSearch and LibreDB (#1327, closes #1321), and numeric columns sort as numbers in the grid (#1482, closes #1384).
NaN,Infinityand-Infinityreach the grid, exports, agent and MCP as words instead of NULL (#1377, closes #1371).- SQLite and libSQL BLOBs show as
\xhex (#1350, closes #1331), and the JSON exports and copies write a binary cell as the same hex instead of a{"type":"Buffer"}object (#1472, closes #1381).
Exports that replay
Export as SQL INSERT now writes values each engine reads back: PostgreSQL arrays, intervals, points and circles, SQL Server BIT, and ClickHouse Array, Map and Tuple (#1483); Trino, DuckDB and Cassandra typed literals (#1490, closes #1386). A cell with no valid literal turns its row into a -- Row N skipped comment, and the INSERT and DDL target the table the SELECT read instead of a generic name. The DDL export keeps types such as integer[] and DateTime64(3, 'Europe/Istanbul') instead of TEXT.
Maintenance, cancel and transactions say what happened
- PostgreSQL and MySQL connections probe the server at connect and offer only the maintenance it runs, so CockroachDB, RisingWave, YugabyteDB, TiDB and Vitess no longer show operations they refuse; a statement's own fault answers 400
QUERY_ERRORwith the engine's sentence instead of 500; and every whole-database card in Admin > Operations asks for confirmation (#1487 closes #1387, #1427, #1438; #1499). - Maintenance from the monitoring page works on tables outside the
publicschema, and the table's schema is passed on SQL Server, DuckDB, MySQL, ClickHouse, Oracle and Couchbase too (#1091, closes #772). - Cancel says "Query Cancelled" only when the engine confirms it, else "Cancel Not Confirmed". ClickHouse can now cancel, CockroachDB, Materialize and RisingWave fall back to the PostgreSQL wire CancelRequest, and on engines that cannot cancel the control reads STOP WAITING (#1383, closes #1364).
- SANDBOX claims "auto-rolled back" only when a rollback succeeded, refuses statements that commit implicitly, and refuses to start where
BEGINopens no transaction (#1324, closes #1317). - The editor's background plan on PostgreSQL-wire servers no longer executes the statement a second time; it uses
EXPLAIN (FORMAT JSON)withoutANALYZE, and multi-statement text is never planned (#1318, closes #1311). - A query stopped by PostgreSQL
statement_timeoutorlock_timeoutis reported as a timeout, not a cancel (#1149, closes #1145).
Security fixes
OIDC: the state cookie was accepted as a session (GHSA-8gc9-2gm6-5c7f). On a deployment with OIDC_ISSUER, OIDC_CLIENT_ID and OIDC_CLIENT_SECRET set, the signed oidc-state cookie that GET /api/auth/oidc/login hands any visitor once the identity provider answers discovery was also accepted as the session cookie, whatever NEXT_PUBLIC_AUTH_PROVIDER was set to, because the login route never checked it. An unauthenticated visitor could pass the session check on every path outside /admin for that cookie's five-minute life, and could request a new one at will. Versions 0.7.0 through 0.17.0 are affected; a deployment that never set those three variables never issued the cookie, so local sign-in on its own is not exposed. The state is now signed with a key derived from JWT_SECRET for that purpose alone, so the session check no longer accepts it, and it carries a token type of its own that the OIDC callback checks (#1380). If you run Studio with OIDC, or have the OIDC_* variables set, upgrade. A sign-in in progress during the rollout fails its state check once; signing in again works.
- DuckDB file access for standard users. A non-admin user's DuckDB connection could read, and in some cases write, any file the Studio process can reach, with
read_textand the other file-table functions orCOPY, and could make the server request URLs; the discovery export of the new CapRover auto-connect template, which holds every discovered database's password, would have been within that reach, so this fix ships with the template. A DuckDB editor handle now opens with DuckDB'senable_external_accessoff for every non-admin role, and for every role on a DuckDB seed a non-admin role can use, so no statement reaches the network or a file other than the database's own files and the handle's private temp directory, while that database stays writable. The database path itself is not sandboxed: a standard user's DuckDB connection still opens, reads and writes any DuckDB-format file the Studio process can reach, and creates a missing one (docs/providers/duckdb.md section 3.16). The posture is derived on the server from the session's role and the resolved connection, never from the request, and a full-reach handle and a denied one are never shared. An admin keeps full reach on an inline connection and on an admin-only seed (#1519). - Server files behind file-based connections. SQLite, DuckDB and LibreDB connections refuse, for every role and before a handle opens, a path that names Studio's storage database, its
-waland-shmfiles, or theauth-bootstrap.jsoncredentials file with its backup and temporary copies, also when the path reaches one through a symbolic or hard link; other database files in the same directory stay usable. SQLite connections also need trusted file access now, since SQLite's drivers cannot confine what a statement reads and writes the way DuckDB's posture does: a SQLite connection opens only for an admin, on an inline connection or an admin-only seed, and agent runs, the agent hand-over and MCP follow the same rule (#1523, #1529). - HTTP database destinations. A new opt-in setting,
DB_HTTP_BLOCK_PRIVATE_HOSTS, refuses connections from the HTTP-based providers (ClickHouse, Couchbase, Druid, Elasticsearch, OpenSearch, libSQL, Prometheus, Trino, and in this release Qdrant and both InfluxDB types) to private and loopback addresses, checking literal IPs and DNS answers at socket connection time, custom TLS paths included. It is off by default, so local database connections keep working; when it is on, HTTP connections through an SSH tunnel are refused too, since their target is a local tunnel endpoint (#1114, closes #1108; #1242). - Next.js moves from 16.3.5 to 16.3.8: 16.3.6 for a critical Next.js vulnerability reported by the dependency scan (#1288, #1172), and 16.3.8 for the security fixes in that release (#1512).
- DuckDB no longer fetches extensions at open. Test Connection on a SQLite file used to make the server download the
sqlite_scannerextension and rewrite the SQLite file. Autoinstall, autoload and community extensions are now off, and a file that is not a DuckDB database is refused unopened (#1476, closes #1404). - Redis commands that moved the shared connection.
SELECT,RESET,AUTHandHELLO, insideMULTItoo, moved every later request on that connection to another database, user or protocol; the editor now refuses them (#1121, closes #1107). - Data masking. The Data Profiler masks min, max and sample values with the same configuration and role as the grid, in its exports and in the AI summary request, which used to send min and max in clear (#1478, closes #1421). Sorting a masked column orders rows by the masked text, so the order no longer reveals the hidden values (#1506, closes #1491), and the column filter matches the masked text (#1492).
- Connection dialog. Closing the dialog after a new connection resets TLS, SSH tunnel, environment and Advanced fields, so the next new connection no longer opens and tests with the previous one's certificates, client key and tunnel (#1150, closes #1125).
- The Db2 driver's linked rustls crates are past the RustSec advisories (#1353).
- The provider cache key. Two connections that differ only in their Elasticsearch API key pair, or only in their MongoDB
authSource, no longer share one cached provider, so a rotated or revoked API key takes effect at once instead of only after the cached provider has sat unused for 30 minutes, and a corrected auth database is not served by a provider opened as the other user (#1510).
Also in this release
MySQL family
- Columns report their declared type, such as
varchar(20)orint unsigned, so Schema Diff migrations for a MySQL or MariaDB target are accepted, and column defaults are written as SQL read fromSHOW CREATE TABLE(#1073 closes #1033, #1119 closes #1031). - Databend, StarRocks and Apache Doris: characters outside the BMP display correctly, statements that return no rows no longer fail, and manual
BEGIN,COMMITandROLLBACKwork with toasts that say Studio cannot verify the transaction there (#1357 closes #1352, #1367 closes #1366, #1473 closes #1470). - Databend, which cannot prepare statements, gets its object tree, column reads, statistics and inline edits through client-side binding, and moves from query-only to partial support (#1479, closes #1474).
- A pasted MySQL connection string gets the same
timezoneZ default as the host and port form (#1134). - Vitess lists its keyspace instead of the sidecar and shard databases, and folders count (#1361, closes #1354). Analyze Table on TiDB, OceanBase and Databend succeeds when the server answers with no report (#1471, closes #1382).
- Explain draws a plan tree for MySQL, MariaDB and Percona Server, and a script run inside
BEGINor SANDBOX runs statement by statement (#1492 closes #1389, #1390, #1396, #1477).
PostgreSQL family
- Server WARNING and NOTICE messages are shown with the result, capped at 100 per statement, and a startup notice shows as a caution at Test Connection (#1488, closes #1401).
- Schema tools: columns whose names are substrings of the key are no longer marked primary key, Schema Diff no longer re-creates the key's own index, Create Table from a schema folder creates the table there, and autocomplete qualifies tables outside the default schema (#1493 closes #1391, #1394, #1395, #1397).
- On Materialize the object tree folders count and open, except Functions and Procedures (#1358, closes #1351).
Oracle, SQL Server, SQLite and DuckDB
- PL/SQL bodies,
/separator lines and T-SQLGObatches split correctly; Oracle used to report success for objects stored INVALID (#1332, closes #1312). - Oracle columns report their declared type,
UROWID(n)andVECTOR(n, format)keep their size, and table statistics read the user's tables instead of always "no tables" (#1187 closes #1139, #1237 closes #1209, #1365 closes #1355). - Pasting an Azure portal ADO.NET string with
Server=tcp:fills the host correctly (#1212, closes #1211). - SQLite returns the rows of
WITH,VALUESandRETURNINGstatements (#1330, closes #1323). - A DuckDB file the process cannot write opens read-only and says why a write is refused (#1476; #1486, closes #1405; #1494).
- libSQL: a connection that names a user signs in to a self-hosted
sqldstarted withSQLD_HTTP_AUTHover HTTP Basic (#1516).
MongoDB, Redis and other non-SQL engines
- MongoDB reads Extended JSON such as
$oidand$date, so a document can be found by its ObjectId (#1368, closes #1363); results show the union of every document's keys (#1376, closes #1372); and Generate Find and the profiler no longer fail with "Path collision" (#1374, closes #1373). - FerretDB lists databases (#1302, closes #1299), and a pasted string with
tlsCAFileor an unescaped@in the password is handled (#1210). - The Keys panel's Scan all no longer freezes the tab after Load more filled the tree, on Redis too (#1228).
- Redis: each editor line is its own command and
SET k ""stores an empty string (#1379, closes #1370); a failed connect names its reason (#1362, closes #1356); and blocking commands the provider refuses no longer ask for confirmation first (#1174, closes #1164). - Cassandra and ScyllaDB Generate Query and imports write CQL that parses, Elasticsearch reports a closed index correctly, Qdrant and InfluxDB no longer hit
ECONNRESETafter about 5 s idle, and the MongoDB grid shows Long, Timestamp, RegExp and UUID readably (#1495 closes #1410, #1413, #1416, #1419, #1423). - A Neo4j disconnect during a connect closes that attempt's driver (#1308, closes #1296).
- Couchbase takes the bucket from the connection string's path, as in
couchbases://host/bucket, when the Database field is empty; a Database value still wins (#1517, closes #1457). - A malformed Kafka read request is a query error, not a config error (#1137, closes #1129). On VictoriaMetrics the Tables tab lists up to fifty metrics (#1162).
Results, editor and charts
- A failed query replaces the previous result with an inline error, also in the embedded workspace, and an object's open tab is focused instead of duplicated (#1136). A multi-statement failure keeps a banner naming the statement (#1475, closes #1385), and a new run clears the previous error (#1316, closes #1294).
- A write shows "N rows affected", Load More is not offered after a last page that ends exactly full, Explain runs go to Query History with a Plan badge, the export menu names masked columns, and deleting a connection removes its saved tabs (#1485 closes #1425, #1433, #1440, #1447, #1448, #1460). CSV import into a new table quotes its names and keeps the dialog open with the error on failure (#1492). The "limited" badge no longer shows on short pages (#1142, closes #1128).
- Profile Table works on every SQL engine with plain aggregates and shows the engine's message for a refused measure (#1349, closes #1320).
- Charts: a NULL category no longer shifts every later value (#1375, closes #1369), and rotated x-axis labels stay out of the legend (#1175, closes #1130).
- A grid column filter ends with the query it was typed against, and matching folds the Turkish dotted and dotless I (#1480, closes #1409).
- The Query Safety Check offers Skip analysis and gives up on the AI after 15 seconds (#1322, closes #1313); it is now a Radix alert dialog with trapped focus (#1191, closes #1185). Confirmation dialogs return focus and follow Studio's theme (#1202 closes #1199, #1204 closes #1198), and labels in the connection, import, pivot and toolbar views render at their intended weight (#1140, closes #1124).
- The inline editor's key-uniqueness check reads its count by name, so an edit on the row whose key is 1 no longer skips it, and Db2 no longer refuses most edits (#1353).
- The code generator keeps a trailing
sin column names (#1177, closes #1138). - Typing in the editor no longer re-renders the Studio shell, and first-load JavaScript drops from 2426.8 kB to 2196.0 kB (#1127, #1190, #1217).
Sidebar, admin and configuration
- Connections can be grouped in collapsible user-defined sections (#1229, closes #1170).
- Monitoring's Pool card reads "Open clients", the audit log lists the newest event first, and empty gauges show N/A (#1481 closes #1434, #1445, #1463, #1464).
- Vault Kubernetes login takes a custom auth mount through
VAULT_K8S_AUTH_PATH, and both Vault path variables ignore surrounding whitespace (#1282 closes #1245, #1297 closes #1291). - The agent's local model roster grows from thirty-five to forty models that passed all six agent surfaces at 30/30 (#1192).
- The login form renders in the first HTML (#1232).
- Trino is called by its own name, not Apache Trino, across docs, READMEs, store listings and packaging metadata, and the README attributes the Apache trademarks (#1158).
Distribution and packaging
- The desktop AppImage no longer bundles
libwayland-client, which left the window white on Mesa 26 hosts (#1236, closes #1222). - An AUR package,
libredb-studio-bin, is ready and stays pending until AUR registration reopens (#1218, closes #971). - The container images move to Node 26.10.0: the default image on
node:26.10.0-trixie-slim, the alpine image onnode:26.10.0-alpine3.23, and the slim alpine image onalpine:3.24(#1171). Runtime dependencies move to monaco-editor 0.57.0, @platformatic/kafka 2.13.0 (each version taken only after the live read-only Kafka and Redpanda suite passed on it), cassandra-driver 4.10.0, pg 8.23.1, mongodb 7.7.0 and mysql2 3.24.5, and adm-zip is held at 0.6.1 for CVE-2026-77301 (#1172, #1512). The README lists ZopDay and Scoop Extras (#1183, #1226 closes #1120), and the Fly.io and Railway pins move to 0.17.0 (#1207). - New Portuguese and Russian READMEs (#1017, #1188 closes #610).
Upgrading
These changes can stop a setup that worked before:
- Local accounts on sqlite or postgres storage.
ADMIN_*andUSER_*now only seed the accounts table on first start; changing them later does not change stored passwords. A startup warning reports a mismatch, andADMIN_PASSWORD_RESET=truerestores the env admin at the next start, ends its sessions and removes its passkeys; remove the variable afterwards, because every start applies it again while it is set. Upgrading such a deployment signs local users out once, and MCP tokens issued before the upgrade stop working and must be created again (#1122). - Storage schema. On sqlite and postgres storage the first start creates the
accounts,passkey_users,passkey_credentialsandpasskey_spent_challengestables, so theSTORAGE_POSTGRES_URLrole needs CREATE on its schema, as it did at first install (#1122, #1195). - API routes without a valid session return 401 with
{"error": "<message>", "code": "AUTH_REQUIRED"}instead of a 307 to/login; pages still redirect. A script or embedding host that relied on the redirect must handle the 401 (#1484). - PostgreSQL TLS to an IP address. With SSL Mode
verify-system,verify-caorverify-fulland a host given as an IP address, the server certificate is now checked against that IP instead of the namelocalhost(pg 8.23.1, #1512). A certificate that lists the IP now connects; one that lists onlylocalhost, reached through127.0.0.1, is now refused, so connect by the name the certificate carries.STORAGE_POSTGRES_URLis affected only withsslmode=verify-system. - libSQL connections that name a user, and no connection string, send HTTP Basic instead of a bearer token; a connection string keeps its bearer token (#1516).
- Sign-in redirects. A signed-out page now redirects to
/login?next=<path and query>, the bare root still to a bare/login, and a signed-in visit to/login?next=goes to that page instead of the role's landing page (#1516). - DuckDB no longer auto-installs or auto-loads extensions; a query that relied on that needs an explicit
INSTALLandLOAD, and community extensions cannot be enabled. A DuckDB connection to a SQLite or other non-DuckDB file is refused (#1476). - DuckDB for standard users. On a non-admin user's DuckDB connection, and for every role on a DuckDB seed a non-admin role can use, file-table reads,
COPYto or from a file, URL reads,INSTALLand theLOADof an extension that is not bundled answer DuckDB'sPermission Error; the connection's own database stays writable, and an admin keeps that reach on an inline connection and an admin-only seed (#1519). - SQLite for standard users. A SQLite connection opens only for an admin, on an inline connection or an admin-only seed. A standard user's SQLite connection, and every role's use of a SQLite seed offered to any role besides
admin, agent runs, the agent hand-over and MCP included, fail at connect with an error saying SQLite needs an administrator; give such a seedroles: ["admin"]to keep it for admins. The bundled Employees SQLite sample is listed for admins only. A SQLite, DuckDB or LibreDB connection to Studio's storage database, its-waland-shmfiles orauth-bootstrap.jsonis refused for every role (#1523, #1529). - Redis editor.
SELECT,RESET,AUTHandHELLOare refused; pick a database with the Keys panel picker or the connection's Database field (#1121). A command wrapped across lines without quotes is refused; write it on one line (#1379). A wrong-password connect answers 401 instead of a retryable 503 (#1362). - SANDBOX refuses DDL and other implicit-commit statements on MySQL and Oracle, refuses to start where
BEGINopens no transaction, and returns 400TRANSACTION_STATE_UNREPORTEDon MySQL-wire servers that report no transaction state, such as Databend, StarRocks and Apache Doris, where a SANDBOX run could autocommit before (#1324, #1473). - SQL Server multi-statement runs send each
GObatch as one request and never send aGOline. Destructive statements inside a control-flow block now open the safety confirmation (#1332). - MongoDB. A
$dateor$oidobject in an insert is stored as a BSON Date or ObjectId instead of a literal subdocument, and a wrapper mixed with another key is refused (#1368). - ClickHouse
Decimalarrives as a string, small values included, so the grid sorts it as text and pivot no longer offers it as a value field. A RedisDBSIZEreply that is not a count is refused instead of shown as 0 keys (#1327). - Schema Diff snapshots saved before this release report spurious type changes on MySQL and Oracle columns, because
ColumnSchema.typeis now the declared type (#1073, #1187). - Exports. JSON exports and copies write binary cells as
\xhex strings instead of Buffer objects (#1472). Copy Cell on a binary value copies the whole value as hex (#1248). SQL INSERT export is unavailable while masking hides any column (#1485). - HTTP API answers. Clients that call the routes directly should check:
- Non-finite numbers come back as the strings
"NaN","Infinity"and"-Infinity"instead ofnullfrom/api/db/query,/api/db/multi-query,/api/db/transaction, agent artifacts and MCP, and a PostgreSQL infinitetimestamptzas"infinity"(#1377). - Statement faults classified by SQLSTATE class or driver code answer 400
QUERY_ERRORinstead of 500, and thePOST /api/db/monitoringpayload gains amaintenancefield (#1487). A PostgreSQLstatement_timeoutorlock_timeoutanswers 408TIMEOUT_ERRORinstead of 499 (#1149). A malformed Kafka read is a query error instead ofCONFIG_ERROR(#1137). options.limitandoptions.offsetthat are not non-negative integers get a 400; the limiter fetches limit + 1 rows, so aSELECT ... FOR UPDATEwithout its ownLIMITin a held transaction locks one extra row (#1485).- An explain request holding more than one statement gets a 400 (#1318). A
queryIdthat is not a string is refused (#1383).POST /api/db/transactionwith a multi-statement query answers in the multi-query script shape plusinTransaction, which now reflects the server state (#1492, #1324). - A wrong-depth container on the object counts, list and inventory routes answers 400 with only an
errorfield (#1148). Object edit routes answer 400 for a body that is not valid UTF-8 and 413 for a declaredContent-Lengthover the limit (#1195). POST /api/db/profileleaves unmeasured figures out instead of sending 0, returns refusals inwarnings[]and capped columns inomittedColumns, ends a timeout or lost connection with 408 or 503, and answers 400 to non-string column names or an empty column list; the profile's CSV and JSON exports write unknown figures as empty (#1349, #1374).POST /api/ai/query-safetycan answer 504TIMEOUT_ERRORafter 30 seconds (#1322).GET /api/admin/auditreturns events newest first andlimit=0returns none (#1481).- A
connectionIdthat is present but empty, or is not a string, answers 400Invalid connection ID format; omit the field to send an inline connection (#1519). - Fleet health resolves every item the way the query routes do, so a connection whose id names a seed is checked as that server-side seed.
/launchis a public path, andPOST /api/auth/launchanswers 404 while launch sign-in is off (#1516).
- Non-finite numbers come back as the strings
- Sidebar. A starred connection appears both under Favorites and in its own section (#1229).
An adopter embedding @libredb/studio should also check the library surface:
DatabaseTypegainsetcd,db2,neo4j,qdrant,milvus,influxdb,influxdb3andoxia.QueryTab["type"]gainsetcd,oxia,cypher,influxql,qdrantandmilvus;ProviderCapabilities.queryDialectgainsetcd,oxia,qdrantandmilvus;queryLanguagegainscypherandinfluxql;identifierQuotinggains"double-always"; theQueryEditorlanguageprop gainsqdrantandmilvus, andKeyScanCapability.totalScopegainsnone. An exhaustiveswitchover any of them needs the new arms.KeyScanPage.totalnow counts whattotalScopedeclares.- Maintenance takes the new
MaintenanceOperationtype,MaintenanceTypepluscompact,defragment,disarm,loadandrelease, inProviderCapabilities.maintenanceOperations,maintenanceOperationSpecsandDatabaseProvider.runMaintenance.MaintenanceOperationSpecgains optionaltitle,description,confirmation("typed"or"typed-target"),kindsandpreview, with the exportedMaintenancePreviewtype. createDatabaseProvider,getOrCreateProviderandwithOneShotTunnelraise aDatabaseConfigErrorforreadOnly: trueon an engine that does not enforce it, and for areadOnlythat is not a boolean.getOrCreateProvidertakes a third argument, the newly exportedEditorExecutionContext, and refuses areadOnlyin it;ProviderExecutionContext, whichcreateDatabaseProvideralready took, is now exported too and gains anallowExternalFileAccessfield. Called without a context, either function opens a DuckDB handle with file and network access closed; pass{ allowExternalFileAccess: true }for the full editor reach (#1519).getOrCreateProviderrefuses a SQLite connection too unless its execution context passes{ allowExternalFileAccess: true }, since an absent context reads as deny;createDatabaseProviderwithout a context keeps SQLite's trusted behaviour. A SQLite, DuckDB or LibreDB path that names the storage database atSTORAGE_SQLITE_PATH(default./data/libredb-storage.db), its-waland-shmfiles or theauth-bootstrap.jsonbeside it raises aDatabaseConfigError(#1523).- The embedded workspace requests
GET /api/connections/policywhen its Schema Diff panel opens; a host without that route answers 404, which reads as allowed (#1516). - Rows carry strings instead of
Dateobjects for PostgreSQLdate,timestampand their arrays, MySQLDATE,DATETIMEandTIMESTAMP, SQL Servertime,dateanddatetime2, and OracleDATEandTIMESTAMP. PostgreSQLinterval,pointandcirclearrive as text, and a top-level json null as the stringnull(#1134, #1505, #1178, #1225, #1503). ColumnSchema.typecarries the declared type on MySQL and Oracle, with the family inbaseType(#1073, #1187).- An
AUTH_REQUIRED401 reaches the host's own code unchanged: embedded components register no session-ended handler (#1484). @libredb/studio/securitygains anallowWebAuthnGetoption; the default output still deniespublickey-credentials-get(#1195).ConnectionModalresets every connection-scoped field when the edit target changes or a new connection is saved with the dialog kept open, and withdraws the previous target's test result (#1157, #1167, #1205).- The exported
DataProfilershows unmeasured figures as unknown and gains optionalmaskingConfig,maskingEnabledanduserRoleprops;DataChartslabels NULL, Date and other non-string categories before drawing (#1349, #1478, #1375). - New optional members, which need no change to compile:
QueryResult.vectorColumns,resultSets(the newQueryResultSettype) androlledBack, with the typesVectorColumn,VectorKind,VectorDTypeandSparseEncoding;WorkspaceQueryResult.vectorColumns;ProviderCapabilities.previewProjectionandpreviewTimeWindowwith the typesPreviewProjection,PreviewProjectionRuleandPreviewTimeWindow;ColumnSchema.provenance;QueryTab.runErrorandorigin;QueryHistoryItem.kind;QueryWarning.severity;DatabaseConnection.readOnly,dataServersandallowInsecureAuth;DatabaseOverview.tableCountSampledFrom;DatabaseObject.readRangeswithObjectReadRange;ObjectKindSpec.enumeratedByandcountIsListing;trailingandpayloadLabelon the command arm ofObjectEditUnit;KeyScanCapability.separator,cursor,patternandtotalScope;KeyScanPage.skipped;ProviderCapabilities.enforcesReadOnly,readsFileAccessPosture,previewProjection,previewTimeWindow,inlineEditRefusedColumns,containerPathShapes,implicitCommitStatements,implicitCommitExceptions,supportsQueryCancel,blocksServerWhileRunning,supportsConstantPredicateandsupportsMultiRowInsert;DatabaseProvider.previewMaintenance,engineUserandconnectWarnings; theQuerySafetyDialogconnectionNameprop and asignalforonAnalyzeSafety.
Helm chart: 0.1.78
Tracks app release 0.18.0. Charts 0.1.72 to 0.1.77 were published against the 0.17.0 image and added config.passkeyOrigin and the metadata for etcd, Neo4j, Db2, Milvus, Qdrant, InfluxDB and Oxia; 0.1.78 is the first chart whose image runs them. Passkeys also need config.storageProvider set to sqlite or postgres: the chart's NOTES warn when config.passkeyOrigin is set with local storage, and on a TLS ingress with sqlite or postgres storage they suggest the origin to set. artifacthub.io/containsSecurityUpdates is true for the OIDC, DuckDB and file-based connection fixes above. The chart's own edit is its description, which now calls Trino by its own name instead of Apache Trino (#1158).
helm repo add libredb https://libredb.org/libredb-studio/
helm upgrade --install libredb-studio libredb/libredb-studio --version 0.1.78
Contributors
- @kaya-abdullah landed the largest share of this release's fixes: the session-ended 401 and its follow-ups (#1484, #1496, #1504); maintenance probes and confirmations (#1487, #1499); cancel, SANDBOX, background plan and query safety (#1383, #1324, #1318, #1322); exact numbers, dates, BLOBs, binary JSON, non-finite values and numeric sort (#1327, #1505, #1350, #1472, #1377, #1482); exports that replay (#1483, #1490); the MySQL family on Databend, StarRocks, Apache Doris, Vitess, TiDB and OceanBase (#1357, #1367, #1361, #1471, #1473, #1479, #1492); PostgreSQL notices, schema tools and Materialize (#1488, #1493, #1358); Oracle statistics and the script splitter (#1365, #1332); SQLite rows (#1330); DuckDB extensions and read-only files (#1476, #1486, #1494); MongoDB and Redis editor fixes (#1368, #1374, #1376, #1379, #1362); five NoSQL fixes (#1495); the profiler, its masking, and the masked sort (#1349, #1478, #1506); charts, grid filter, monitoring and results fixes (#1375, #1480, #1481, #1485, #1475); the first Db2 password fix (#1301); and VictoriaMetrics metrics (#1162).
- @nawazish2 built storage for more than two local accounts with Admin > Accounts (#1122), connection groups in the sidebar (#1229) and the chart label fix (#1175).
- @Dharshni-gth co-authored passkey sign-in (#1195).
- @DevvoLazza added the guard on HTTP database destinations (#1114).
- @koraysrn took per-keystroke renders of the Studio shell to zero and cut first-load JavaScript (#1127, #1190, #1217).
- @yusuf-gundogdu grew the agent's local model roster to forty (#1192), corrected the CapRover install text (#1203), made the image scan fail on fixable Critical findings (#1182), and kept the store listings and deployment pins current (#1160, #1176, #1207, #1208).
- @Aditya-XR fixed Oracle dates, the Redis commands that moved the shared connection, and the Neo4j disconnect race (#1225, #1121, #1308).
- @iAmAdheil made MySQL and Oracle report declared column types and fixed the code generator's trailing
s(#1073, #1187, #1237, #1177). - @sloemo01 sent the table's container with maintenance targets and unified the container-path sentence (#1091, #1092).
- @NormanSMA added the AUR package (#1218), @rivolity the Vault Kubernetes auth mount (#1282), @Lingikaushikreddy MySQL default SQL for Schema Diff (#1119), @methakon SQL Server dates and a connection dialog fix (#1178, #1205), @Reitzzz the PostgreSQL timeout report (#1149), @stroexd PostgreSQL interval and point text (#1503), @MFA-G the connection dialog reset (#1150), and @rahimahisah17 the Next.js update (#1288).
- @chiliec (#1137, #1157), @KodYazicam (#1167, #1304), @hridhinvarkeyjoseph (#1302), @hasnaintypes (#1210), @abkucuk (#1212), @niukanen1 (#1174, #1140), @lb1192176991-lab (#1297), @rnihesh (#1316), @fatihcvs (#1142), @shivamcoderrrr (#1191), @Object-ions (#1202, #1204), @Retsumdk (#1194) and @brown-sussy (#1517).
- Documentation and translations: @paulocoutinhox (#1017), @Fristail27 (#1188), @ArthurRamonSouza (#1206), @kaya-abdullah (#1158, #1161, #1223, #1469, #1489), @rnihesh (#1314, #1315), @cestercian (#1307), @chiliec (#1153, #1166), @KodYazicam (#1168, #1306), @lb1192176991-lab (#1298), @fatihcvs (#1141), @niukanen1 (#1219), @muskanbandta23 (#1183), @JaredAung (#1226), @gurkanceylan41 (#1234), @Maaz2212 (#1220, #1221), @berkay-byte (#1280), @lui01212 (#1300), @mgr-punith (#1319, #1465) and @DevKhizerer (#1360).
- Reported by @nktnet1 (#772, #784, #785), @nycjay (#786, with the earlier Db2 work in #787), @yusuf-gundogdu (#1108, #1233), @kaya-abdullah (#1299, #1432), @yizhixiaokong (#1170) and @dreamstack-net (#1222).
etcd, IBM Db2, Neo4j and the Graph tab, Qdrant, Milvus, InfluxDB, Oxia, passkey sign-in, the OIDC fix, CapRover and DigitalOcean discovery, launch sign-in for hosting platforms, the DuckDB file-access fix, the reserved server files and admin-only SQLite, PostgreSQL dates, the inline failed-run error and the AppImage fix are by @cevheri.
Full changelog: 0.17.0...0.18.0