Skip to content
Tinker
Download

Native macOS · PostgreSQL · MySQL · MariaDB · SQLite · Redis

Every edit becomes SQL you read before it runs.

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

  • macOS 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 122 ms — and the same rows are one click from being a chart.

A row of coordinates is not a place. A page of numbers is not a trend.

Three panes that answer the question you opened the table to ask, without a copy into anything else.

A geometry column is a place, so it opens as one.

Points, lines and polygons drawn on Apple Maps at the coordinates the server holds — PostGIS, MySQL spatial, or a text column holding WKT. Click a shape to select its row.

Read the docs

The rows you just ran, drawn — one click from the grid.

Pick a value and what to group it by, and the rows you just ran become a bar, line, area, pie or scatter. A key is never offered as a value, because summing an id says nothing.

Read the docs

Autocomplete that has read your schema, not just a keyword list.

After FROM orders t, typing t. lists that table’s columns with the type the server declared. Functions arrive with their signatures, and the match is fuzzy: cst finds customers.

Read the docs

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.

Auto-commit was on, and the cell you just changed was the wrong one.

Press ⌘Z. Every write carries its own way back, worked out before it ran, and Put Back refuses a row somebody has changed since rather than overwriting it.

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 setting up a new Mac, and there are twenty connections on the old one.

File › Back Up Connections… writes them all to one file, folders included, with the passwords sealed under a passphrase you type. Drop it on the window on the new Mac, and a production connection comes back marked production.

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.

The table you need is in MySQL and the database you are building is PostgreSQL.

Transfer, data sync and structure sync take any pair of connections. The table is rebuilt in the target’s own types, the rows arrive as its literals, and whatever could not cross — views, routines, triggers — is named when the transfer finishes.

The column holds a geometry and you need to know where that is.

Open the Map tab. Points, lines and polygons are drawn on Apple Maps at the coordinates the server holds — no tile key, no browser, no pasting a pair of numbers into a map site.

You did not want the rows. You wanted to know whether it is going up.

The Chart pane sits next to Rows: pick the value and what to group it by. When it drew a page rather than the whole result it says so, because a partial sum must never read as the total.

Someone sends you two hundred rows in a spreadsheet.

⌘V in the grid. Each value lands in its own column — quoted cells, line breaks inside a cell and CRLF ends included — and on a production connection they wait for Commit like any other edit.

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.

You add a foreign key and cannot remember whether the column is customer_id or cust_id.

You do not type it. The table, its key and your column are picked from lists of what the server has, choosing customers finds customer_id on its own, and a key the server would refuse — types that differ, a target that is not unique — is flagged before it is sent.

The row is right and the page is still wrong, because the cache is Redis.

Open the Redis connection beside it. Keys by pattern and type, each in the view its type needs — hashes, streams, JSON, time series, Bloom filters — and a console that prints what redis-cli prints and refuses a write on a read-only connection.

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.

  • Read-only sets the session read-only on the server. Production never auto-commits, and dropping a table means typing its name.
  • TLS by default, SSH tunnels in pure Swift, and passwords in the Keychain — leaving it only sealed, inside a connections backup you make.
  • A SQLite file is a connection with no host, port or password — drop it on the window.
Read the docs

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

  • An AppKit NSTableView over server-side paging, at 60 fps. No web view, no Electron.
  • Deep pages switch from OFFSET to keyset paging, because OFFSET degrades.
  • The status bar names the row range and the elapsed time on every tab, so no speed claim here has to be taken on trust.
Read the docs

An editor that knows your aliases and your dialect.

  • ⌘R runs the statement at the cursor, ⌘⌥R a 2,000-statement dump — DELIMITER $$ procedures included.
  • Each tab carries its own connection and database, and ⌘. cancels on the server within a second.
  • Results under the editor or beside it, with Chart and Map offered wherever the rows can fill them.
Read the docs

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

  • Nothing mutates as you type. Preview diffs your edits against the server, and it is the only route to Execute.
  • MySQL commits DDL implicitly — the preview says so, and asks you to name the table.
  • Structure sync writes the DDL that makes a target match a source, across engines included.
Read the docs

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