Skip to content
Tinker
Download

Connections and safety

Production mode, read-only mode, TLS and SSH tunnels are enforced on the server session, not painted on the UI.

A SQLite file is a connection

SQLite has no server, so it has no host, port, user or password. Drop a .sqlite or .db file on the window, open it from Finder, or pick it from the File menu, and it is a connection like any other: tables, structure, queries, export and dump all behave the same way they do against a server.

  • Foreign keys are enforced by default, which is not SQLite's own default.
  • Read-only holds on the file itself, not only on the session, so a connection marked read-only cannot be written through by any route.
  • lower() and upper() fold more than ASCII, so a case-insensitive comparison behaves the way the rest of the app does.
  • The status bar reads Local file where a server connection names its transport, because there is no wire to encrypt.
Note
Everything below this point is about connecting to a server. None of it applies to a SQLite file, which is why the connection editor asks for a file and stops.

Which engine you are looking at

Each connection wears its engine’s own logo on a white tile in the sidebar, so it reads the same in light and dark — PostgreSQL’s elephant, MySQL’s dolphin, MariaDB’s sea lion, SQLite’s feather, the Redis mark. MariaDB is its own choice in the connection editor and shows its logo from the start, before the connection has ever been opened, though it uses the same driver as MySQL. That choice is only where it starts: MySQL and MariaDB share a dialect, a wire protocol and often a port, so the server’s own word decides. If the server turns out to be the other one, the logo corrects itself the first time it connects, and the connection keeps that badge while it is closed.

A Redis connection has no tables, so it does not open as a grid: it opens as its keys, a console and the server, and the Redis page of these docs covers it. Its read-only and production switches mean what they mean here.

Production connections

Mark a connection as Production and Tinker changes its behaviour, not just its colour. A production connection never auto-commits — not for a grid edit, and not for a statement typed in a query tab, where the Auto-commit checkbox gives way to a red MANUAL COMMIT mark and every write waits in a transaction for Commit or Rollback. The commit preview’s Execute button is disabled for 1.5 seconds and labelled with the connection name in red. Destructive actions such as Truncate and Drop require the table name to be typed.

A read opens no transaction: SELECT 1 on a production tab leaves nothing open and no Commit to press. What counts as a write is decided by what the statement does, not by its first word — a SELECT that locks the rows it reads (FOR UPDATE and its kin), a WITH … SELECT … INTO, or one that calls a built-in that changes something (nextval, setval, pg_terminate_backend) is held in a transaction on production and refused on a read-only connection, like any other write.

Read-only connections

A read-only connection sets the session read-only on the server (SET default_transaction_read_only on PostgreSQL, SET SESSION TRANSACTION READ ONLY on MySQL). Commit is disabled in the grid. ⌘⇧L unlocks it for the current session only; the stored connection stays read-only.

TLS

New connections require TLS. The mode picker offers the usual set, plus a CA file, a client certificate and key, and a server-name override. What matters is what was negotiated, not what was asked for: the status bar shows the transport the session actually holds, and it says plainly when a connection is not encrypted.

SSH tunnels

Enable SSH on a connection and Tinker forwards a local port through the host before it connects. Authentication is by password or key file, with a passphrase where needed, and a jump host can sit in between. The tunnel is pure Swift over SwiftNIO (Citadel); nothing shells out to ssh. Known hosts are checked and a changed host key is reported, not accepted.

Note
SSH agent authentication is not available in 0.1 (ADR-0013). Use a key file with a passphrase instead.

Where secrets live

Passwords and passphrases are stored in the macOS Keychain under the service com.tinker.connection. The connection store at ~/Library/Application Support/Tinker/store.sqlite holds only a reference to them. A test greps the store file to prove no secret ever lands there. Query history and error logs are redacted before they are written. The one way a secret leaves the Keychain is inside a connections backup you make, and there it is sealed.

Backing up and restoring connections

File › Back Up Connections… writes one .think file holding every connection — TLS, SSH with its jump host, options, colour, the production and read-only marks — together with the sidebar folders, their order and whether they were open. File › Restore Connections… puts it all back, and so does opening the file from Finder or dropping it on the window. It is how a second Mac is set up without typing every host again.

  • Passwords, SSH passwords and key passphrases travel sealed: AES-GCM under a key derived from a passphrase you type, with 600,000 PBKDF2 rounds. The file’s header is authenticated along with them, so a sealed box lifted from another backup will not open in this one.
  • Everything else is plain JSON that can be read, compared and kept, and the file is written readable by you alone. A sealed copy of the connections and folders travels beside it, and a restore refuses a backup whose readable part has been edited — a host pointed elsewhere, TLS turned off.
  • A restore matches connections by identity rather than by name, so restoring the same backup twice changes nothing unless you ask for the backup’s version to win. It never connects to a server, and a production connection comes back marked production.
  • A backup names any password the Keychain refused to give rather than leaving it out in silence, and a restore names the connections it could not finish.

Connection errors

A failed connection opens a sheet that names the stage where it failed (DNS, TCP, SSH, TLS, auth), quotes the underlying message verbatim, and offers Retry. Connecting to a stopped server surfaces the TCP stage within the timeout instead of hanging.

A connection the server has closed behaves the same way. When PostgreSQL ends an idle session — an administrator’s pg_terminate_backend, idle_session_timeout, a failover — the next statement on it fails at once as a lost connection, rather than leaving the tab busy, so Tinker can reconnect.

Pooled connections

A session keeps a small pool. Before a pooled connection is reused, it is reset: open transactions are rolled back, session variables cleared, and the search path or database restored. One tab’s state never leaks into another’s.