Workspace level
The cross-database layer. Every connection in one place; activity, search, and schema diff that span them all.
What lives here
| Surface | What it shows |
|---|---|
| **Connections** | Every connection registered in your zanith.config.ts plus any added at runtime via the UI. Per-row state: connected / idle / error, latency to the host, last-seen timestamp. |
| **Activity** | Last 200 queries across every connection, with the source (Studio tab, plugin, your app), the SQL, and the elapsed time. Filter by connection, by latency band, by free-text on the SQL. |
| **Search** | Free-text across schema (table / column / index names), recent SQL, recent migrations. The keyboard shortcut is ⌘K / Ctrl+K. |
| **Schema diff** | Pick two connections, get the structural diff between them. Useful for catching drift between staging and production. |
| **Command palette** | ⌘K again — every action that has a CLI flag has a palette entry. Disconnect a connection, run a saved query, jump to a table. |
Adding a connection
# Permanent — declare it in zanith.config.ts so the next launch sees it.# Studio reads the same config the engine does. # Ad-hoc — add via the UI. Stored in ~/.zanith/connections.json on the host# running Studio. Visible to anyone with shell access to that host.Ad-hoc connections persist for that host only — a teammate launching Studio against the same engine will not see them. That's intentional: per-user adapters belong in per-user state, not in the shared config.
The activity feed
Activity reads from the same plugin hook as structuredLogger — Studio registers an in-memory sink that keeps the last 200 entries per connection. Restart Studio and the buffer clears; it is not persisted.
// Studio's sink is registered automatically. To also ship the same events// to your log aggregator, register your own structuredLogger alongside.plugins: [ structuredLogger({ sink: (r) => log.info(r) }),],Schema diff
Pick a left connection and a right connection. Studio runs introspectPostgres on each, builds two SchemaGraph instances, runs diffSchemas against them, and renders the result as a structured op list — the same shape migrate generate produces.
# The same diff, from the CLI:zanith db diff --left $STAGING_URL --right $PROD_URL