diff --git a/databases/duckdb.mdx b/databases/duckdb.mdx
index 278fcc0..61de121 100644
--- a/databases/duckdb.mdx
+++ b/databases/duckdb.mdx
@@ -105,6 +105,10 @@ Read-only is not a way to keep writing from somewhere else. A read-write connect
Releasing hands the file to whoever wants it next, which may not be you. A query run after another process has taken it fails until that process lets go; reconnect once it has.
+## Back up and restore
+
+**File > Backup Dump…** runs over the open connection. It copies the whole database into a `.duckdb` file, or exports it as a folder of Parquet files. **File > Restore Dump…** takes the `.duckdb` file. For the folder, and what each format carries, see [Backup & Restore](/features/backup-restore#what-a-dump-carries).
+
## Limitations
- A DuckDB file takes one writer at a time. A connect against a file another process holds fails, naming that process and its process ID. Quit the `duckdb` CLI, the Python process or the other TablePro window first, or set **Release the File Lock After**.
diff --git a/features/backup-restore.mdx b/features/backup-restore.mdx
index bde2f4c..8bfd68a 100644
--- a/features/backup-restore.mdx
+++ b/features/backup-restore.mdx
@@ -92,16 +92,20 @@ Each database runs on its own. A failure stops that one and the run carries on,
-No `--clean` is passed, so restoring on top of a schema that already holds conflicting objects produces errors instead of replacing them. A DuckDB restore behaves the same way, and reports the first object whose name is already taken.
+No `--clean` is passed, so restoring on top of a schema that already holds conflicting objects produces errors instead of replacing them. A DuckDB restore behaves the same way, and reports the first object whose name is already taken. SQLite stops at the first error, and a dump TablePro wrote is one transaction, so none of it is kept: restore it into an empty database file.
Restore covers the whole file. There is no table picker on the way back in.
+A MySQL, MariaDB or SQLite restore runs the file as SQL and nothing else. The client's own commands in it, `source` and `system` for MySQL and MariaDB or `.read` and `.shell` for SQLite, are not run, and `LOAD DATA LOCAL INFILE` is refused.
+
## What a dump carries
`mysqldump` runs with `--single-transaction --routines --triggers --events`, so a MySQL dump is consistent with itself and carries stored routines, triggers and scheduled events. `pg_dump -Fc` carries the whole database. `sqlite3 .dump` writes the schema and every row as SQL.
DuckDB writes one of two things. A `.duckdb` file carries tables, views, indexes, foreign keys and sequences, and only DuckDB reads it, which is also true of `pg_dump`'s archive and MongoDB's. A Parquet folder holds `schema.sql`, `load.sql` and one Parquet file per table, which pandas, Spark and BigQuery read directly. Pick the file to restore into TablePro later, the folder to hand the data to something else.
+The folder restores too, except on TablePro 0.83.1 and 0.84.0-beta.2, where **File > Restore Dump…** takes only the `.duckdb` file. The folder is imported first into a separate DuckDB instance that can read nothing outside it, then copied into the database. A `schema.sql` or `load.sql` that reaches for another file, a database or an extension fails there, and the database is left as it was.
+
## SSH tunnels and SSL
Both flows reuse the connection's active SSH tunnel, with no second port forward. The whole of the connection's SSL configuration reaches the tool, the CA certificate and the client certificate and key included: PostgreSQL takes them in `PGSSLMODE`, `PGSSLROOTCERT`, `PGSSLCERT` and `PGSSLKEY`, and MySQL and MariaDB in their client's own flags. SQLite and DuckDB open a file, so neither applies.
@@ -159,7 +163,7 @@ SqlPackage is the exception. It accepts a password only inside its connection st
## Failures
-A non-zero exit shows the last 64 KB of the tool's stderr in a scrollable monospaced view, and DuckDB's own error text in the same place. Four causes account for most of them.
+A non-zero exit shows the last 64 KB of the tool's stderr in a scrollable monospaced view, and DuckDB's own error text in the same place. Most come down to one of these.
| What you see | What to do |
|---|---|
@@ -169,5 +173,6 @@ A non-zero exit shows the last 64 KB of the tool's stderr in a scrollable monosp
| *"could not tell whether … is MySQL's client or MariaDB's"* | The tool on `PATH` did not answer `--version`, and the two families take different SSL flags. Reinstall `mysql-client` or `mariadb` |
| Objects that conflict with the dump | Restore into a fresh database, or drop the conflicting objects first |
| *"a single transaction can only write to a single attached database"* | A DuckDB query tab has an open transaction that has already written. Commit or roll it back, then run the backup again |
+| *"The backup could not be imported, so this database was not changed. …"* | A DuckDB Parquet folder failed in its separate instance, and DuckDB's error follows. Check that `schema.sql` and `load.sql` name only files in that folder, or restore a `.duckdb` backup |
One non-zero exit is not a failure. A `pg_restore` newer than the server sets parameters the server does not have, such as `transaction_timeout` on anything before PostgreSQL 17, and exits 1 after restoring everything. When those are its only errors, the restore reports complete and names the settings the server skipped. Any other error in the same run still fails it. So does a server whose `lc_messages` is not English, because its errors cannot be read.
diff --git a/features/favorites.mdx b/features/favorites.mdx
index 9ea2225..d803771 100644
--- a/features/favorites.mdx
+++ b/features/favorites.mdx
@@ -201,6 +201,8 @@ When a linked folder sits inside a Git working copy, a changed file carries a le
A file with no letter matches its last commit. Letters refresh when a file changes, when the repository changes, and when you switch back to TablePro.
+The letters come from a status read with every Git filter switched off, so a file that Git LFS or git-crypt rewrites can show **M** until you stage it.
+
@@ -230,5 +232,5 @@ Only the checked files are staged and committed. Files outside the linked folder
While a command runs, a spinner sits on the folder's row and the Git commands are hidden. When one fails, the alert shows what Git printed.
-Link only repositories you trust. Reading a file's status runs the repository's own content filters, and committing, pulling, and pushing run its hooks, exactly as `git` in Terminal does.
+Link only repositories you trust. **Commit…**, **Pull**, and **Push** run the repository's hooks and filters, exactly as `git` in Terminal does.
diff --git a/features/project-folder-import.mdx b/features/project-folder-import.mdx
index d4beaf3..5ffa45d 100644
--- a/features/project-folder-import.mdx
+++ b/features/project-folder-import.mdx
@@ -62,6 +62,8 @@ The one file it reads outside the folder you picked is `wp-config.php` one level
Some settings point elsewhere instead of holding a value, like `${{Postgres.DATABASE_URL}}` on Railway or a Rails credential lookup. Those are left out rather than guessed at, so a row you expected can be missing. Fill those in by hand, or paste the URL with [Import from URL](/connections/urls).
+A `${VAR}` reference is filled from the `.env` files in the folder, never from your shell or TablePro's environment, and Spring config gets only the default in `${VAR:default}`. A value that needs a variable from your shell is not filled in: type it into the form before you save.
+
## Related
- [Connection Sharing](/features/connection-sharing) for importing from other database apps