From 7d368d272f3538eff4de10bcc935d35006989dfd Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Wed, 21 Oct 2026 14:26:54 +0700 Subject: [PATCH 1/2] docs(databases): attach more files to a SQLite, libSQL or DuckDB connection --- databases/duckdb.mdx | 4 ++-- databases/libsql.mdx | 2 +- databases/sqlite.mdx | 16 +++++++++++++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/databases/duckdb.mdx b/databases/duckdb.mdx index ecfd5ed9..43f667af 100644 --- a/databases/duckdb.mdx +++ b/databases/duckdb.mdx @@ -76,7 +76,7 @@ A connection opens one database named after the file: `analytics.duckdb` becomes ATTACH 'warehouse.duckdb' AS warehouse; ``` -Press `Cmd+K` to move between them, in place, with no reconnect. DuckDB does not persist attachments, so a reconnect starts again from the one file. `system` and `temp` are hidden, and with them `information_schema` and `pg_catalog`. +Press `Cmd+K` to move between them, in place, with no reconnect. An `ATTACH` typed in the editor lasts until the next connect. To keep a file attached, add it under **Attached Databases** in the connection's **Options**: every connect attaches it again, named after its file without the extension, and a file that is missing is named in a warning while the rest attach. `system` and `temp` are hidden, and with them `information_schema` and `pg_catalog`. Any connection can also read a file straight from SQL: @@ -99,7 +99,7 @@ Three ways out, in **Options** on the connection: **Database ▸ Release File Lock** hands it back now, without ending the session. The tabs, the schema cache and the row you were on all stay; the next query takes the file again. -A release is refused, with the reason, while the session holds anything reopening would destroy: an open transaction, a temporary table or view, an attached database, or a changed setting. Commit the transaction or drop the temporary table and the release goes through. +A release is refused, with the reason, while the session holds anything reopening would destroy: an open transaction, a temporary table or view, a database attached from the editor, or a changed setting. The connection's own **Attached Databases** attach again on reopen. Commit the transaction or drop the temporary table and the release goes through. Read-only is not a way to keep writing from somewhere else. A read-write connection blocks every other process, read-only ones included; a read-only connection blocks writers. Two readers work, a reader and a writer do not. diff --git a/databases/libsql.mdx b/databases/libsql.mdx index b6355c4f..1b6e7957 100644 --- a/databases/libsql.mdx +++ b/databases/libsql.mdx @@ -35,7 +35,7 @@ There is no host, no port and no Database field: the URL names one database and |-------|-------------| | **Database File** | Path to the file. **Browse…** picks one, **New…** names one that does not exist yet, and `~` expands. A path that does not exist is created, along with any missing folders | -The API Token field is hidden here; a local file needs no authentication. **Options** gains an **Extensions** list in this mode, which loads SQLite extensions the way it does for [SQLite](/databases/sqlite#extensions). +The API Token field is hidden here; a local file needs no authentication. **Options** gains two lists in this mode: **Attached Databases**, which attaches more files the way it does for [SQLite](/databases/sqlite#attached-databases), and **Extensions**, which loads SQLite extensions the way it does for [SQLite](/databases/sqlite#extensions). Do not open a file that is being synced as a Turso embedded replica while the owning app is running. Concurrent access to a syncing replica can corrupt it. diff --git a/databases/sqlite.mdx b/databases/sqlite.mdx index 9aff99f2..4976f5c3 100644 --- a/databases/sqlite.mdx +++ b/databases/sqlite.mdx @@ -49,7 +49,19 @@ The sidebar lists tables and views and hides the internal `sqlite_*` tables. Eac Change the file outside TablePro and the object list reloads on its own. Rows already loaded in a tab stay until you refresh that tab. -One connection is one file, with no database to switch between, and the object list reads the main database only: a file you `ATTACH` in the editor is queryable as `alias.table` but never appears in the sidebar. +## Attached databases + +A schema split across files, such as `app.db`, `auth.db` and `audit.db`, fits in one connection. Open the connection's **Options**, click **+** under **Attached Databases**, and choose the other files. Each one is named after its file without the extension, so `auth.db` attaches as `auth`. Type over the name in its row to change it; `main` and `temp` are taken. + +```sql +SELECT u.email, e.action +FROM auth.users u +JOIN audit.events e ON e.user_id = u.id; +``` + +The list attaches again on every connect, before anything runs: a reconnect, **Test Connection**, a relaunch and a restored tab all see `auth.users`. Each attached database is a row of its own in the sidebar, below the main file's tables. Expand it to browse its tables and edit their rows, and the editor completes `auth.` with its tables. A file you `ATTACH` in the editor joins the sidebar after a refresh, until the next connect. + +A file that is missing when the connection opens is named in a warning at the top of the window, and the rest still attach. ## Extensions @@ -118,6 +130,8 @@ A virtual table, such as an FTS5 table, cannot be recreated from what SQLite sto - Encrypted databases do not open. The driver's SQLite takes no key, and the form has nowhere to put one. Decrypt a SQLCipher file with the `sqlcipher` tool first. - Extensions load only for a file opened on this Mac. A connection that runs **On the Server** refuses a list with `Extensions load only for a database file on this Mac`: remove the list, or open the file **As a Read-Only Copy**, which loads it. +- Attached databases also open only on this Mac, and a connection that runs **On the Server** refuses the list the same way. +- A table in an attached database has a read-only Structure tab, and its sidebar menu offers no Export, Import, Transfer or Copy To. Do those from a connection that opens that file. - A column that is `INTEGER PRIMARY KEY` cannot be retyped: the key would stop generating values and start storing NULL. The save is refused and names the column. - A primary key cannot be added, removed or moved. From 1bfb8e6a1e064a19ba8a16786b93dd093bb914af Mon Sep 17 00:00:00 2001 From: Ngo Quoc Dat Date: Wed, 21 Oct 2026 14:56:56 +0700 Subject: [PATCH 2/2] docs(databases): DuckDB attachments follow the read-only setting --- databases/duckdb.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/databases/duckdb.mdx b/databases/duckdb.mdx index 43f667af..86d55364 100644 --- a/databases/duckdb.mdx +++ b/databases/duckdb.mdx @@ -76,7 +76,7 @@ A connection opens one database named after the file: `analytics.duckdb` becomes ATTACH 'warehouse.duckdb' AS warehouse; ``` -Press `Cmd+K` to move between them, in place, with no reconnect. An `ATTACH` typed in the editor lasts until the next connect. To keep a file attached, add it under **Attached Databases** in the connection's **Options**: every connect attaches it again, named after its file without the extension, and a file that is missing is named in a warning while the rest attach. `system` and `temp` are hidden, and with them `information_schema` and `pg_catalog`. +Press `Cmd+K` to move between them, in place, with no reconnect. An `ATTACH` typed in the editor lasts until the next connect. To keep a file attached, add it under **Attached Databases** in the connection's **Options**: every connect attaches it again, named after its file without the extension, and a file that is missing is named in a warning while the rest attach. With **Open the File Read-Only** on, they attach read-only as well. `system` and `temp` are hidden, and with them `information_schema` and `pg_catalog`. Any connection can also read a file straight from SQL: