Skip to content
Tinker
Download

Every edit becomes SQL you read before it runs.

A native macOS client for PostgreSQL, MySQL and MariaDB — and for the SQLite file on your desktop, which you open by dropping it on the window. Built for the developer who is in dev in the morning, staging after lunch, and production over SSH at five.

Download DMGGitHubmacOS 14+ · Apple Silicon · free for noncommercial use
A query over a 1,000,000-row table: the first page of 1,000 rows, back in 152 ms.

You already have a database client. These are the moments that decide whether you keep it.

You change a cell and press Commit.

Every statement it generated appears first, syntax-highlighted, with a count. Nothing runs until you press Execute.

The UPDATE would have matched two rows, not one.

The whole transaction rolls back. Nothing is written, your edit buffer is still there, and Tinker tells you the count it actually got.

You open a table with a million rows in it.

One page of 1,000 rows opens, and one page is all that stays in memory. Sorting, filtering and paging happen in the database, not in the app.

The server rejects your statement.

You get the server’s own sentence and its SQLSTATE, with a squiggle under the offending token. No rewriting, no summarising, no silent retry.

You are connected to production.

The mode is set on the server session, not painted on the UI. Nothing auto-commits, and dropping a table means typing its name.

You have a .db file on your desktop and you want to look inside it.

Drop it on the window. There is no host, no port and no password — the file is the connection, and it gets the same grid, structure designer, editor and export as any server.

The preview is the easy half. The guard is the row count.

Tinker builds each statement from the primary key and the values the row held when it loaded. It runs them in one transaction, counts the rows each one touched, and rolls the whole thing back unless that count is exactly one.

exactly one row, or ROLLBACKWHERE holds the values the row had at loadno primary key, no editing — and the status bar says why
How a commit works
UPDATE orders SET status = $1 WHERE id = $2;DELETE FROM orders WHERE id = $1;INSERT INTO orders (customer_id, total)VALUES ($1, $2) RETURNING *;
The shapes of the SQL a grid edit turns into — printed here, not captured. SET carries only the columns you changed; WHERE carries the primary key as it was when the page loaded.

None of that is a rendering. These are the four screens you will live in, running.

Production is a mode on the server, not a colour in the UI.

  • 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.
  • A production connection never auto-commits. Execute is disabled for 1.5 seconds and wears the connection’s name, and dropping a table means typing that table’s name.
  • TLS is required for new connections, and the status bar names the transport the session actually negotiated — not the one you asked for.
  • SSH tunnels in pure Swift over NIO, with password, key file and jump-host auth. Passwords live in the macOS Keychain and nowhere else.
  • A SQLite file is a connection with 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.
  • On that file, foreign keys are enforced by default, a read-only connection holds on the file itself rather than only on the session, and lower() and upper() fold more than ASCII.
Read the docs

A million rows, and a thousand of them in memory.

  • An AppKit NSTableView over server-side paging: one page of at most 1,000 rows, scrolling at 60 fps. The SQL editor is an NSTextView. There is no web view and no Electron anywhere in the app.
  • Deep pages switch from OFFSET to keyset paging, because OFFSET degrades. The status bar tooltip tells you which one it used.
  • Inline editing with a typed editor per column, NULL handling, and composite or UUID primary keys.
  • That status bar names the row range and the elapsed time on every tab, so you never have to take a speed claim on trust — including the one on this site.
Read the docs

An editor that knows your aliases and your dialect.

  • Autocomplete reads the statement you are writing: after FROM users u, typing u. lists the columns of users.
  • Run the statement at the cursor, the selection, or all 2,000 statements in a pasted dump — DELIMITER $$ procedures included.
  • Each tab carries its own connection and database, so you write SELECT * FROM t and it resolves against that tab’s session.
  • ⌘. cancels on the server with pg_cancel_backend or KILL QUERY and returns within a second, leaving the connection usable.
Read the docs

Change a schema the way you change a row: read it first.

  • The structure designer never mutates anything as you type. Preview diffs your edits against introspection, and it is the only route to Execute.
  • MySQL commits DDL implicitly. The preview says so, lists the statements that will not roll back, and asks you to name the table.
  • SQLite’s ALTER TABLE cannot express every column change. Those are applied by rebuilding the table inside one transaction, the way SQLite’s own documentation prescribes.
  • Structure sync writes the DDL that would make a target match a source, across engines. Destructive statements are listed apart and unchecked.
Read the docs

That is the whole argument. What is left is the evidence for it, and the download.