Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Schemaic guide

Schemaic is a native SQL editor for MySQL, MariaDB, PostgreSQL, SQLite and SQL Server. This guide covers the parts where people most often need a hand: finding your way round a database, changing its structure, and the tools built on top of that. It is not a reference to every control — the interface is meant to explain itself, and the guide picks up where it doesn't.

How to read it

  • Bold text is always an interface label, spelled exactly as it appears in the app — a menu entry, a button, a tab — such as Edit table. If you can't find one, you may be on an engine that doesn't offer it; each page says where that's the case.
  • Keys are written as Ctrl+P.
  • In the schema tree, right-click also means the keyboard's menu key, or Shift+F10, on the selected row.

Engines are not all equal

MySQL/MariaDB, PostgreSQL and SQL Server are fully supported. SQLite reads, writes, imports and edits tables, views and triggers, but has no manual-transaction mode and no users to manage. Where an engine can't do something, Schemaic leaves the entry out rather than showing it greyed out — a greyed-out entry usually means the connection is marked read-only.

Found something wrong or missing? Every page has an edit link at the top that opens its source on GitHub.

Getting started

This page takes you from nothing to a first query: install Schemaic, connect it to a database, and run something.

Installing

Every release is on the Releases page, built for Windows and Linux on x86_64 and for macOS on Apple Silicon.

  • Windows — download and run Schemaic-win-x64-Setup.exe. It installs for your user only, so it needs no admin rights, and it keeps itself up to date. The installer isn't code-signed, so SmartScreen warns you the first time: click More info, then Run anyway. If you want a copy that doesn't install or update, use the portable .zip instead.

  • macOS and Linux — run the install script:

    curl -fsSL https://raw.githubusercontent.com/fadion/schemaic/main/install.sh | bash
    

    On macOS it puts Schemaic in /Applications, and the app updates itself from then on. On Debian and Ubuntu it adds Schemaic's signed apt repository, and on Fedora, RHEL and openSUSE its dnf/zypper repository, so Schemaic updates along with the rest of your system. On any other distribution it installs the self-updating AppImage. The script asks for sudo, and prints how to uninstall when it's done.

If you'd rather install by hand — the .dmg on macOS, or adding the repository from https://fadion.github.io/schemaic yourself — the project's README has the steps, including the fingerprint to check the signing key against.

The self-updating builds check for a new release in the background. When one has downloaded, a Restart to update button appears in the header. Set the environment variable SCHEMAIC_NO_UPDATE_CHECK=1 if you don't want Schemaic to check.

Your first connection

On first launch there's nothing to connect to yet, so the header shows New connection where the connection switcher will go. Click it.

  1. Give the connection a Name, and pick its Type: MySQL (also for MariaDB), PostgreSQL, SQLite or SQL Server.
  2. For a server, fill in Host, Port, User and Password. Database is optional. For SQLite, pick the Database file instead.
  3. Press Test to check that Schemaic can reach the server, then Save.

Saving connects. The SCHEMA panel on the left fills with the server's databases, and the connection's name takes the place of New connection in the header.

The password goes to your operating system's keyring, not into a file. Everything else on the form — SSH tunnels, SSL / TLS, read-only mode and the rest — is covered in Connections.

Your first query

Press Ctrl+T for a new query tab, type a statement, and press Ctrl+Enter. Schemaic runs the statement under the caret, and the rows appear in the grid below the editor. On macOS, use Cmd wherever this guide says Ctrl.

To see a table's rows without writing anything, double-click the table in the schema tree.

Where to go next

  • Connections — more connections, tunnels, sign-in and safeguards.
  • Query editor — completion, running several statements, transactions.
  • Results grid — editing rows, filtering, exporting.
  • Schema — finding your way round a database and changing its structure.
  • Keyboard shortcuts — or press the question-mark button in the header.

Connections

A connection is one saved server — or, for SQLite, one database file. You add and change them in Manage connections, and switch between them from the header.

Managing connections

Open the connection switcher in the header and choose Manage connections at the bottom of its menu. Your saved connections are listed on the left, and the selected one's settings on the right.

  • New connection adds one and selects it.
  • Test tries the settings as they stand, without saving them. If it fails, hover over the message to read the whole reason.
  • Save stores the changes and connects.
  • Right-click a connection in the list for Duplicate and Delete. Deleting removes the connection's stored password, its AI conversation, its query history and its tabs along with it.

Import connections and Export connections sit next to New connection; see Importing connections.

The form

The form has four sections.

SectionWhat it holds
GeneralName, Colour, and an optional Folder to group connections under
SafeguardsRead-only mode and the other limits on what can happen through the connection
DatabaseEnvironment, Type, where the server is and how to sign in, and Init SQL
NetworkSSH tunnel and SSL / TLS

The Database section changes with Type:

  • MySQL, PostgreSQL, SQL Server — Host, Port, Database, then User and Password. Changing the type changes the port to the new engine's default (3306, 5432, 1433) unless you've typed your own. Database is optional; it's the one the connection opens in, and some hosted providers refuse a connection that doesn't name it. For MariaDB, choose MySQL.
  • SQL Server named instances — write the host as server\instance. SQL Server Browser then supplies the port, so Port is ignored.
  • SQLite — just a Database file. There's no server, so no host, password, tunnel or TLS, and the Network section goes away. SQLite statements commit as they're sent: there's no manual transaction mode.

Where an engine offers more than a password, an Authentication picker appears above User. See Signing in and TLS.

Switching connections

Click the connection's name in the header to open the switcher, and pick another. Each connection keeps its own tabs, query history and AI conversation, so switching back puts you where you were. From the keyboard, open the command palette (Ctrl+Shift+P) and use Switch connection.

Connections with a Folder are listed under it, in the switcher and in Manage connections alike. Hover over a connection whose name or address is cut short to see it in full.

If a connection drops, the header says Disconnected, with a Retry button.

Telling connections apart

Three settings help you see at a glance which server you're on — useful when staging and production look the same.

  • Colour marks the connection in the switcher and on the switcher's border.
  • Prominent colour in editor also frames the query editor in that colour.
  • Environment — Local, Development, Testing, Staging or Production — adds a badge with that name to the header.

You can also colour individual databases in the schema tree, which tints their query tabs; see Schema.

Where passwords are kept

Passwords, SSH passwords and SSH key passphrases go to your operating system's keyring — Credential Manager on Windows, the Keychain on macOS, the Secret Service (GNOME Keyring, KWallet) on Linux. Everything else is saved in connections.json, in %APPDATA%\schemaic on Windows and ~/.config/schemaic elsewhere.

If no keyring is available, such as on a Linux machine with no Secret Service running, Schemaic keeps working by leaving the password in connections.json in plain text. Schemaic needs no password for Windows, Microsoft Entra or cloud IAM sign-in, and stores none.

In this section

  • Signing in and TLS — Windows, Microsoft Entra and cloud IAM sign-in, and encrypting the connection.
  • SSH tunnels — reach a server through an SSH host, with jump hosts and ~/.ssh/config.
  • Safeguards — read-only mode, command-line and AI access, timeouts and init SQL.
  • Importing connections — bring connections over from other tools, and share your own.

Signing in and TLS

Most connections sign in with a user and a password. Where an engine offers another way, the connection form shows an Authentication picker above User.

Sign-in methods

MethodEnginesWhat it needs
User and passwordAll but SQLiteUser and Password
Windows (this account)SQL Server, on Windows onlyNothing — the account Schemaic runs as
Microsoft Entra (Azure CLI)SQL ServerThe Azure CLI, signed in with az login
AWS IAM (AWS CLI)MySQL, MariaDB, PostgreSQLUser, and the AWS CLI signed in
Google Cloud IAM (gcloud)MySQL, MariaDB, PostgreSQLUser, and the Google Cloud CLI signed in
  • Windows signs in as the Windows account Schemaic is running under. The server must know that account as a Windows login. The option is only there in the Windows build.
  • Microsoft Entra signs in as whoever is signed in to the Azure CLI. Run az login first. Use it for Azure SQL Database and other servers that accept Entra accounts.
  • AWS IAM and Google Cloud IAM are for Amazon RDS and Cloud SQL. They sign in as the User you give, with a token from the cloud's own command-line tool — run aws configure or aws sso login, or gcloud auth login, first. On RDS the user needs the rds_iam role (PostgreSQL) or the AWSAuthenticationPlugin (MySQL).

With the last three, Schemaic asks the CLI for a token each time it needs one and never saves it. If the CLI isn't signed in, the connection fails with a message saying which command to run.

An Azure SQL serverless database that has paused takes about a minute to wake. The first connection wakes it but may time out; connect again shortly.

Encrypting the connection

SSL / TLS, in the form's Network section, decides whether the connection is encrypted, and how much Schemaic checks the server's certificate. Each step up adds to the one before it.

ModeWhat it does
DisableConnects in plain text. The default for a new connection.
PreferEncrypts if the server offers it. Doesn't check the certificate.
RequireRefuses to connect without encryption. Doesn't check the certificate.
Verify CAEncrypts, and checks the certificate against a trusted authority.
Verify fullAlso checks that the certificate is for the host you connect to.

Only Verify CA and Verify full protect you from someone in the middle; the first three keep out eavesdroppers at best. On MySQL and MariaDB, Verify CA checks the host name too, so it behaves as Verify full.

The certificate fields appear once you pick a mode that encrypts:

  • CA certificate, with the two verifying modes — leave it empty to trust the certificate authorities your operating system trusts, including any your organisation has installed. Name a file to trust only that one; for RDS or Cloud SQL, this is where the provider's CA bundle goes.
  • Client certificate and Client key — only for servers that ask you to prove who you are (mutual TLS). Both must be PEM files, and the key can't be passphrase-protected.

Token sign-in sets a floor on encryption, whatever mode you picked: Microsoft Entra always connects at Verify full, AWS IAM at least at Require, and Google Cloud IAM at least at Verify CA. The form tells you when this happens.

SSH tunnels

When a database server can't be reached directly — it only listens on a private network, or behind a bastion host — Schemaic can reach it through an SSH server that can. Every connection Schemaic opens then travels through the tunnel; you don't need to start one yourself.

Setting one up

In the connection form's Network section, turn on SSH tunnel and fill in:

  • SSH host and SSH port — the machine you can SSH into.
  • SSH user, and under Authentication how to sign in to it:
    • Password, typed in SSH password;
    • Key pair, with the Private key file and its Passphrase if it has one;
    • SSH agent, which leaves the signing to your running agent — the OpenSSH agent, or Pageant on Windows. Schemaic stores no key. If the agent has no keys loaded, run ssh-add.

Host and Port in the Database section stay as the SSH host sees them. A database on the SSH host itself is usually 127.0.0.1.

SQLite has no tunnel, since there's no server to reach. A SQL Server named instance (server\instance) can't be reached through a tunnel either, because SQL Server Browser answers over UDP; give the server's host and the instance's own port instead.

Jump hosts

If the SSH host is itself only reachable through other hosts, list them in Jump hosts, comma-separated and nearest first — as OpenSSH's ProxyJump does. Each one signs in the same way as the SSH host.

Using ~/.ssh/config

You can give a Host alias from your ~/.ssh/config as the SSH host. Schemaic reads the file each time it opens the tunnel and fills in what the form leaves empty — the real address, port, user, key and ProxyJump — as ssh <alias> would. A note under the field shows the route it found.

Some things in the file Schemaic doesn't follow: a ProxyCommand, a Match block, or a jump host's own ProxyJump. When the route depends on one of those, the note says so; give the route as Jump hosts instead.

Host keys

The first time Schemaic connects to an SSH host it hasn't seen, it checks the host's key against your ~/.ssh/known_hosts. If the host isn't listed there, Schemaic trusts the key and remembers it.

If the key later changes, Schemaic refuses to connect and shows both fingerprints. That can mean the server was rebuilt — or that something is intercepting the connection. Check the new fingerprint with whoever runs the server before you trust it; the message says what to remove so that Schemaic records the new key.

Safeguards

The Safeguards section of the connection form limits what can happen through a connection. Each setting belongs to one connection, so a scratch database and a production server can be set up differently.

Read-only

Turn on Read-only for a connection you only mean to look at. Schemaic then refuses to change anything through it:

  • The query editor runs reads only. A write or a change to the structure is refused with Read-only connection and the reason, and the read itself runs in a session the server holds read-only, so a statement that looks like a read but writes is caught too.
  • The results grid's cells can't be edited, and rows can't be added or deleted.
  • In the schema tree, entries that would change something are greyed out. Where an editor still opens, such as the table designer, its SQL preview has no Apply: you can read and copy the SQL, but not run it.
  • Restoring a backup into the connection, copying a table into it, killing sessions and cancelling queries in the activity panel are all refused, and the terminal won't open the database's own command-line client for it.

On SQL Server there's no read-only session to ask for, so Schemaic runs each statement in a transaction and rolls it back. A procedure that does something outside the database — sends mail, writes a file — can still have that effect. For a real guarantee, connect with a login that can only read. A read-only SQL Server connection also can't hold a manual transaction.

Read-only guards against mistakes; it isn't a security boundary. If it matters that nothing can be written, give the connection a database account that has no write privileges.

Command-line and AI access

  • CLI access lets the schemaic command line use this connection, and AI agents through schemaic mcp. It's off for every connection until you turn it on. See Command line.

  • AI data access sets how much of the database's data Schemaic's AI assistant may see. Its structure — names, types, definitions — is always available to it.

    LevelWhat leaves your machine
    Schema onlyNo rows at all, and attaching rows to a question is refused
    Only what I attachThe rows you attach from a result yourself. The default.
    Let it read dataWhatever the assistant reads with its own read-only queries

    See AI assistant.

Statement timeout

Statement timeout cancels any statement on this connection that runs longer than the time you pick. Same as the app follows the timeout in Settings › Query.

Init SQL

Init SQL, in the Database section, holds settings to apply every time Schemaic connects — a search path, a time zone, a role:

SET search_path TO app, public;
SET TIME ZONE 'Europe/London';

On SQLite it takes PRAGMA settings instead.

It only accepts session settings Schemaic knows are safe. It refuses anything that isn't a SET (or a PRAGMA on SQLite), anything that changes the server rather than the session, and the few settings Schemaic's own guards rely on: transaction and read-only settings, autocommit, MySQL's sql_mode, a character set other than UTF-8, and the like. The line under the box says what's wrong as you type, and a connection whose init SQL would be refused doesn't connect.

Importing connections

If you're coming from another database client, you don't have to type your connections in again. In Manage connections, choose Import connections.

Where they can come from

SourceHow
A URLPaste it into Connection URL and press Add
Clients on this machineScan installed clients
Running containersDocker containers
A fileChoose a file…
  • A URL can be a mysql://, mariadb://, postgresql://, sqlserver:// or sqlite: URL, a JDBC URL, a DATABASE_URL= line copied from a .env file, or a SQL Server connection string (Server=…;Database=…). Paste several, one per line.
  • Scan installed clients looks where other tools keep their connections: DBeaver, DataGrip and the other JetBrains IDEs, and the command-line clients' ~/.my.cnf, ~/.pgpass and ~/.pg_service.conf.
  • Docker containers lists the database containers Docker is running here, with the port each publishes to this machine.
  • A file is any of the above saved somewhere else, or a file made by Export connections.

Choosing what to import

Nothing is saved until you press Import. Until then you get a list of what was found, each row ticked, with a note where something needs your attention:

  • No password in the source — DBeaver and DataGrip keep passwords where Schemaic can't read them. Type the password into the connection after importing. For PostgreSQL, Schemaic may find it in your own ~/.pgpass instead; such a row says Password taken from your own .pgpass.
  • Already saved — you already have a connection to the same server. The row is shown, unticked, in case the saved one is out of date.
  • Signs in a way Schemaic can't — give it a SQL login after importing.

Untick what you don't want and press Import. Imported passwords go to the keyring, like any other.

Read-only mode and the environment badge are never brought over from another client: set them on anything that matters before you use it. See Safeguards.

Sharing your connections

Export connections saves your connections to a file you can give to a colleague, or import on another machine. The file leaves out every password, SSH password and key passphrase, and resets CLI access and AI data access — permission to use a database from the command line, or to show its data to an AI, is given on each machine, not carried with the file. Paths to keys and certificates stay in it.

Query editor

The query editor is where you write and run SQL. Each tab is one editor with its own connection and database, and the results of its last run sit underneath it.

Tabs

Ctrl+T opens a new tab on the active connection, and Ctrl+W closes the current one. The database a tab runs against is the selector in the QUERY header above the editor; a tab with none chosen reads No database.

You want to…Do this
Switch tabsCtrl+Tab, or Ctrl+1…9
Rename a tabDouble-click its title
Keep a tab from being closedRight-click it › Pin
Get back a tab you just closedCtrl+Shift+T
Copy a tab, text and allRight-click it › Duplicate

A pinned tab has no ×, and Close other tabs and Close all tabs leave it alone; Unpin it to close it. Tabs come back when the app starts again unless you turn off Restore tabs on startup in Settings. A tab can also be a .sql file on disk — see SQL files.

If a database has a colour (see Schema), its tabs carry it too.

Running SQL

Ctrl+Enter runs SQL. What it runs depends on where you are:

  • With a selection, it runs exactly what's selected. A selection holding several statements runs them all.
  • With just a caret, in a tab holding one statement, it runs that statement.
  • With a caret, in a tab holding several, a small menu opens with the statement under the caret outlined: Run current (already selected — press Enter) or Run everything.

Every statement that's run gets its own result in the strip under the editor, so a Run everything over three SELECTs gives you three results to flick between. Results and what you can do with them are in Results grid.

With several carets and no selection, nothing runs: select what you mean, or go back to one caret.

Parameters. Write :name anywhere a value goes — WHERE id = :id, or even LIMIT :n — and a row of fields appears under the editor, one per name. Each has a chip that says what kind of value it is (text, number, NULL or raw SQL); click it to change. The run waits until every parameter has a value. Values are kept for the session only.

What asks before running

Some statements stop at a bar above the editor before they run. There are two kinds of stop.

Refused outright — nothing you press will run it:

  • the connection is marked read-only and the statement writes, or isn't one Schemaic can prove only reads;
  • the tab has no database and the statement needs one.

Asked first — the bar says why, and Run anyway goes ahead:

  • a statement that destroys rows wholesale: DELETE or UPDATE with no WHERE, TRUNCATE, DROP TABLE, DROP DATABASE, DROP SCHEMA, CREATE OR REPLACE TABLE, and similar;
  • any write at all, while Confirm before running writes is on (Settings › Query). It's on by default;
  • a run that would replace a result holding edits you haven't committed yet.

Whether a connection is read-only shows at the bottom of the window as Read-only or Write mode (amber). Click it to switch. The same guard covers every other way Schemaic runs your SQL — the AI assistant, the command line, a script file — and none of them is laxer than this one.

Transactions

Each tab is in one of two modes, shown at the bottom of the window. Click it to switch.

  • Auto-commit (the default) — every statement is committed as soon as it runs.
  • Manual — the tab holds its own connection and a transaction stays open across runs until you end it. While one is open the footer counts the statements in it and shows Commit and Rollback. Closing the tab, or switching it back to Auto-commit, asks which you want first.

A few things the server decides, not Schemaic:

  • MySQL and MariaDB commit an open transaction before running DDL such as CREATE or ALTER. Schemaic tells you when that has happened, since Rollback can no longer undo what came before.
  • PostgreSQL stops a transaction at the first failed statement. The footer then reads Tx aborted — rollback to continue.
  • SQLite has no Manual mode in Schemaic, so the switch isn't shown: every statement commits as it runs. Nor does a read-only SQL Server connection.

Panels beside the editor

The buttons at the top right open panels in a column beside the editor: Query history and Snippet library (see History and snippets), the AI assistant (AI assistant), Server activity, and the Terminal.

The Terminal (Ctrl+`) is a shell of your choice — pick it under Settings › Terminal. Its database button opens the connection's own command-line client (mysql, psql, sqlite3, sqlcmd) already signed in. It isn't offered on a read-only connection, since the client wouldn't be read-only.

In this section

  • Writing SQL — completion, checks as you type, formatting, find and replace.
  • History and snippets — find what you ran, and keep what you'll run again.
  • Query plans — see how the server will run a statement.
  • SQL files — open and save .sql files, and run a whole script.

Writing SQL

The editor knows the schema of the database a tab is on, and uses it to complete, check and explain what you type. None of this runs anything: the server only sees your SQL when you run it.

Completion

The completion list opens as you type and offers what fits where the caret is — tables after FROM, that table's columns after WHERE, a function's name, a keyword. Pick with ↑/↓ and Enter or Tab.

  • Ctrl+Space opens it where it didn't open on its own. Press it again to widen the list to every database and schema on the connection, not just the tab's own.
  • After JOIN, the list offers whole joins along foreign keys, with the ON condition written for you.
  • After SELECT *, a row offers to expand the * into the table's columns.
  • A table written after FROM or JOIN gets a short alias from its initials — orders o, order_items oi. Turn this off under Settings › Editor › Table aliases.
  • Items you've picked before rank higher next time.

Inline predictions are the faint text after the caret: the likely rest of what you're writing, such as the BY after GROUP, the columns to group by, or the rest of a line you've written before. Tab takes all of it, Ctrl+→ one word, Esc turns it down. Both settings live under Settings › Editor: Inline predictions, and Predictions from past statements if you'd rather your old queries didn't show up.

Reading as you write

  • Hover over a table, column or function for a summary: its columns, type, default, arguments.
  • Ctrl+click a name to open it — a table's data, at the column for a column, or a routine's editor.
  • Squiggles mark syntax errors and mistakes the editor can see without the server, such as a column missing from GROUP BY. Where there's an obvious fix, Alt+Enter applies it. The count at the bottom of the window jumps to the first one.
  • Live database validation (Settings › Query) goes further: on each pause it asks the server to prepare the statement under the caret, without running it, and shows the server's own error. It costs a round trip to the server, so it's off unless you turn it on.

Formatting

You want to…Press
Format the selection, or the whole tabCtrl+Alt+L (Format code)
Format only the statement under the caretCtrl+Alt+Shift+L (Format statement)
Put a statement on one lineCtrl+Alt+J (Make single line)

How formatting looks — keyword case, leading or trailing commas, wrap width, aligned columns — is set under Settings › Code formatting. Names, strings and comments keep their case whatever you choose.

Find and replace

Ctrl+F opens the find bar over the editor, Ctrl+H opens it with a replace field. Its toggles are Match case, Whole word, Regular expression and Find in selection; Replace changes the current match and All every one. Ctrl+G goes to a line.

The right-click menu

Right-click in the editor for what applies to the statement under the pointer:

  • Plan — the statement's query plan. See Query plans.
  • Format statement, Make single line, Copy as single line.
  • Find usages lists every place a table alias, CTE or column alias is used in the statement. Rename alias (or Rename CTE) renames it everywhere at once, and refuses a new name that would change what the query reads.
  • Create view from a SELECT.
  • With the AI assistant on: Ask AI, Explain and Optimise. See AI assistant.

Every other editing key — comments, moving lines, duplicating, case — is in Keyboard shortcuts.

History and snippets

Query history is a record of what you've run. The Snippet library is the SQL you've chosen to keep. Both open as panels from the buttons at the top right of the window, and both are searched by Find anywhere (Ctrl+P) too.

Query history

Every statement you run is recorded with the connection and database it ran on, how long it took, and whether it failed. The panel groups them under TODAY, THIS WEEK and EARLIER, newest first, with a search box above.

  • Click a row to open it in a new tab. A row from another connection switches to that connection first.
  • Right-click a row for Open in new tab and Delete.
  • Current shows this connection's history; All shows every connection's, each row headed with where it ran.
  • The bin button clears the history of the current connection only, after asking — even while All is showing.

Schemaic keeps the newest 200 statements per connection. A statement that carries a password — CREATE USER … IDENTIFIED BY, ALTER LOGIN … PASSWORD and the like — is never recorded.

Snippets

A snippet is a named piece of SQL. Click one in the library to insert it at the caret, replacing the selection if there is one; Open in new tab on its right-click menu puts it in a tab of its own.

Saving one. Write the SQL in the editor and press the library's save button. The new snippet appears at the top of the list with its name ready to type.

Where it shows. A new snippet belongs to the connection you saved it on. Right-click it › Show in to widen it to This connection, every connection of the same engine (for example Every PostgreSQL connection), or All connections. The library groups snippets under the same three headings, narrowest first.

Editing one. Right-click › Edit opens a dialog for the Name, the Query, and an Expansion shortcut: a short word that, typed in the editor, offers the snippet in the completion list. Accept it and the word is replaced by the snippet's SQL.

Placeholders. Write :name in a snippet where a value belongs. After inserting it, the first :name is selected so you can type over it, and Tab moves to the next. A :name left in when you run becomes a parameter (see Query editor).

Built-in snippets ship with Schemaic for each engine — common checks like running queries or table sizes — marked Built-in. They can't be edited or deleted; Duplicate one to get a copy you can change.

Snippets are saved on this machine. Settings › General › Settings file exports them with your preferences, except snippets that belong to a single connection.

Query plans

A query plan is the server's own account of how it will run a statement: which indexes it uses, which tables it reads in full, where it sorts. Schemaic shows it in a table and points out the parts that are usually slow.

Opening one

Right-click a statement in the editor and choose Plan. The Query plan window opens on that statement with its :name parameters filled in, the way a run would send it.

The table is the server's own plan, laid out as the engine returns it — EXPLAIN rows on MySQL and MariaDB, EXPLAIN QUERY PLAN on SQLite, the indented plan on PostgreSQL, and on SQL Server one row per operator with its estimated rows and cost.

Analyze

By default the plan is an estimate: the statement isn't run. Turn on Analyze to run it and see real row counts and timings instead (EXPLAIN ANALYZE, ANALYZE on MariaDB, or SQL Server's actual plan). SQLite has no such form, so there the plan stays an estimate.

Because that runs the statement, Analyze is only offered for a statement that reads. For one that writes, the toggle is replaced by Analyze unavailable (statement writes data). On a read-only connection, a plan of a statement that writes can be refused outright.

Potential issues

Under the table, Potential issues lists what's worth a look:

  • a full table scan, or a sequential scan on PostgreSQL;
  • a sort or temporary table the query builds on the fly;
  • on SQL Server, the indexes the server says are missing — with the improvement it expects — and its own warnings, such as a join with no condition or a sort that spilled to tempdb.

These are hints, not verdicts: a full scan of a ten-row table is the right plan.

Ask AI sends the statement and its plan to the AI assistant, to explain the plan or suggest a change. See AI assistant.

SQL files

A query tab can be tied to a .sql file on disk, so you can keep queries and migrations with the rest of your project. A file far too big to edit — a dump, say — is run as a script instead.

Opening and saving

You want to…Do this
Open a file in a tabCtrl+O, or right-click a tab › Open file
Save the tabCtrl+S, or Save
Save under another nameCtrl+Shift+S, or Save as
Throw away your editsRight-click the tab › Reload from disk

A file opens in a tab of its own, on the active connection. If that file is already open there, Schemaic switches to its tab rather than opening it twice. Saving a tab that has no file asks for a name, as Save as does.

A file tab shows a small file icon before its title, and its title turns italic when it has edits you haven't saved. Hover the tab to see the file's full path. Closing a tab with unsaved edits asks first; the file on disk is left as it was.

When the file changes elsewhere. If another program changes the file while it's open, a bar above the editor says so when you come back to Schemaic: Reload takes the version on disk, Keep mine keeps what's in the tab. Schemaic won't save over a file that has changed since it was opened — reload it, or Save as under another name.

Large files. Schemaic checks the whole tab as you type, so a big file makes the editor slow. A file over 8 MB asks before it opens; one over 64 MB won't open in a tab at all. Run that one as a script instead.

Running a whole script

To run a .sql file — a dump, a migration, a seed script — without opening it, right-click a database in the schema tree and choose Import. Schemaic summarises what the file does before anything runs, then runs it with progress and a way to stop. See Running a SQL script.

Results grid

Whatever you run lands in the RESULTS pane under the editor, as a grid. Opening a table from the schema tree lands there too, in a tab of its own. The grid reads, sorts and filters what came back, and — where the rows come from a table Schemaic can identify — edits it and writes the changes back.

Results and the strip

One run gives one result. Running several statements at once gives one result per statement, and the strip along the top of the pane lists them as chips; click a chip to show that result. Hover over a chip to see the full statement, how long ago it ran, and how much memory it holds.

Right-click a chip for:

  • Pin / Unpin — a pinned result stays when you run again. The next run replaces only the unpinned ones, so you can keep a "before" while you change things.
  • Close, Close other results, Close all results — the last spares pinned results.
  • Compare with … — set this result against another one in the tab. See Comparing results.

A pinned result is a snapshot, and it is read-only: the status line and its chip say kept — read-only, and editing, filtering, paging and re-reading are all switched off on it. Writing back from rows that may be twenty minutes old would quietly overwrite whatever changed since. Pinned results stay in memory until you close them.

When a statement fails, its error appears under the SQL in the editor, beside Explain and AI fix, rather than in the grid.

Reading the grid

The status line above the grid says which database the result came from, how many rows and columns it has, and how long it took: world · 100 rows · 15 cols · 1 ms.

  • Big results are capped. A query stops reading at the Default row limit in Settings (200,000 rows unless you change it), and the line says (capped) — or 200k of ~4.2m rows where the table's size is known. Click read all rows (or read 1m rows, on a very big table) to fetch more.
  • Table tabs page. A table opened from the tree shows 100 rows at a time, with ‹ Rows 101–200 › arrows on the status line. Any single-table SELECT with a fixed LIMIT gets the same arrows.
  • Headers say what a column is — its type under its name, a key icon for primary keys, indexes and foreign keys (when the table was opened with its schema loaded), and a faint ∅ when the column can hold NULL.

Click a cell to select it; Shift+click, Shift+arrows or a drag selects a block, and a click in the row-number gutter selects whole rows. Select cells in one column and a readout at the bottom shows their count, nulls, distinct values and, for numbers, sum, average, median, min and max. Click a figure to copy it.

You want to…Do this
Find a valueCtrl+F, then Enter for the next match
Jump to a rowCtrl+G and type a number — 200k works too
Select everythingCtrl+A
See one row as a formRight-click a cell › Edit row (or View row)

Sorting and filtering

Click a column header to sort by it: ascending, then descending, then back to unsorted.

Where the result comes from a single table with a key — a table tab, or a plain SELECT … FROM one_table — the sort and filter go to the server: Schemaic re-runs the query with an ORDER BY or WHERE, so they cover the whole table, not just the rows on screen. Those results also get a filter bar labelled WHERE: type a condition, such as age > 30 AND city = 'Oslo', and press Enter. The ✕ at its end clears it.

Right-clicking a cell adds to that filter in one move: Filter by this value or Exclude this value. Each adds its condition to what is already there with AND.

Any other result — a join, a query with a GROUP BY — sorts the rows already read, in memory. If the result was capped, the line says sorted subset (capped) — not the full order.

A sort, filter or page change re-reads the rows, so it is refused while you have unsaved edits: Commit or discard your changes first — re-reading the rows would throw them away.

Arranging columns

Drag a header's right edge to resize a column; double-click it to fit the column to its content. Right-click a header for the rest:

  • Freeze keeps the column at the left while the others scroll. Freeze as many as you like; their headers are hatched. Unfreeze lets one go.
  • Hide column takes it off screen. While any are hidden, Show hidden columns (N) brings them back one at a time, or all at once with Show all — and the # corner of the grid turns into an eye with the count.
  • Format as changes how the values look, never what they are: Timestamp reads an epoch number as a date, Number grouping adds separators, File size shows bytes as 1.5 MB, Boolean shows 0 and 1 as false and true. Schemaic remembers the choice for that column. None clears it.
  • Copy name, Copy qualified name and Copy values — see Copying and exporting.

Following relations

A foreign key is a link, both ways:

  • Follow relation on a foreign-key cell — or Ctrl+click on it — opens the table it points at, in a new tab, filtered to the row it names.
  • Referenced by lists the tables whose foreign keys point at this row's table. Pick one to open it filtered to the rows that point at this row.

Both need the table's schema to be loaded, and both work on saved rows only — a row you have added but not committed has nothing to follow yet.

The RESULTS title bar has two more ways into the table behind the result: Table properties… and Live monitor…. They dim when the result doesn't come from a single table.

In this section

  • Editing data — change cells, add and delete rows, and how the changes reach the database.
  • Copying and exporting — the clipboard, the file formats, and exporting every row of a capped result.
  • Charts — a bar, line or histogram of the result.
  • Comparing results — what changed between two runs of a query.

Editing data

You edit a result in place: change cells, add and delete rows, then commit. Nothing reaches the database until you do, and what you commit runs as one transaction.

What can be edited

A cell can be edited when it comes straight from a table column and Schemaic can tell which row it is — the table's primary key, or a unique key with no NULLs, has to be in the result. On SQLite a table with no key is edited through its hidden rowid.

  • Not editable: computed columns (price * qty, COUNT(*)), a table with no usable key, any result on a connection marked read-only, and a pinned result.
  • A join can be edited cell by cell when each table's key is in the result. Adding, cloning and deleting rows needs a result from a single table.

The right-click menu tells you which case you are in: it offers Edit row where something in the row can be written, and View row where nothing can.

Changing cells

Double-click a cell, or press Enter, to edit it. Enter keeps the change, Tab keeps it and moves to the next editable cell, Esc throws it away. A changed cell turns green. It is staged: on screen, waiting to be committed.

  • Set to NULL and Set to DEFAULT on the cell's right-click menu stage those values. Typing the word NULL stages the text NULL; a NULL shows in italics, text does not.
  • Ctrl+V pastes a block copied from the grid or a spreadsheet, starting at the selected cell. A single copied value fills the whole selection — the quick way to set a column to one value. A pasted NULL is a real NULL. What couldn't be pasted (read-only columns, rows marked for deletion) is counted in the note at the bottom.
  • Fill down and Fill up, with several rows selected, copy the top or bottom row's values into the rest.

Columns whose values are spelled out get a control instead of a text box. Booleans and ENUMs open a list to pick from. A SET picks one member at a time in a cell, and shows every member as a chip in the row panel. Dates and times keep their text box, with a calendar beside it and Today or Now to fill in the present.

Adding, cloning and deleting rows

The buttons at the right of the status line do these:

  • Add a row appends a blank row at the bottom, marked *. Cells you leave empty show what the server will fill in — <auto>, <default>, <null> — or <required>, which the row can't be saved without.
  • Clone the selected row adds a copy of it, leaving out auto-increment columns so the server numbers the copy. Duplicate row on the right-click menu does the same; with rows selected in the gutter, it copies all of them, and asks first past 500.
  • Delete row, or Del, marks the selected rows in red for deletion. Undo delete, or Del again, unmarks them.

Committing

The ✓ button shows how many changes are waiting; its tooltip reads Commit 3 changes (Ctrl+Enter). Press it, or Ctrl+Enter, to write them. The ✗ beside it (Discard all pending changes) drops them, and the copy icon (Copy the changes as SQL) puts the statements on the clipboard instead, to read or to run elsewhere.

Here is what a commit does:

  1. Schemaic turns each change into one statement — a DELETE per deleted row, an UPDATE per changed row, an INSERT per new row — that finds its row by the key.
  2. It runs them all in one transaction, deletes first, then updates, then inserts.
  3. Every statement has to affect exactly one row. If any of them affects none or more than one, the whole commit is rolled back and nothing is written.

That last rule is the safety net. It fires when the row you edited has been deleted by someone else since you read it (zero rows), or when the key isn't as unique as it looked (two rows) — the cases where writing anyway would change the wrong data. When it fires, the error appears at the bottom of the grid and your green edits stay, so you can re-run the query, look, and try again.

The net checks that the row is still there, not that it is unchanged. If someone else changed a different column of the same row, your UPDATE still finds the row and writes over their value, so re-run a result that has been open a long time before editing it.

On success, updated rows are refreshed in place; adding or deleting rows re-runs the query.

  • In a Manual transaction tab, the commit goes into your open transaction, and is permanent only when you commit that.
  • On a MySQL MyISAM table, there is no transaction to roll back. If a commit fails part-way, Schemaic says so rather than claiming nothing was written.
  • If another session holds a lock on a row you are writing, the commit waits, and a note at the bottom says so. When the lock is held by one of your own tabs, the note offers Roll back Query 2 (named after that tab) to release it.

The row panel

Edit row opens the row as a form at the bottom of the results pane, one field per column, with the full value in each. Use it for long text or JSON. A json or jsonb column opens as a tree you can expand and edit leaf by leaf; invalid JSON outlines the field in red.

The panel's ✓ saves that row straight away, as its own commit, with the same one-row rule. It doesn't commit the green edits waiting elsewhere in the grid.

Binary values

The grid shows a binary value as its size, <2048 bytes>, because it doesn't hold the bytes. Double-click the cell, press Enter, or choose Edit binary (View binary where it can't be written) to open it:

  • Preview shows PNG, JPEG, GIF, BMP, WebP and icon images; Hex shows any value byte by byte.
  • Save to file writes the value out.
  • Load from file puts a file's bytes in the cell, staged like any other edit — commit in the grid to write it.

The panel reads up to 64 MiB of a value.

Generating rows with AI

The ✦ menu (Generate rows with AI…) has AI fill value, AI insert row and AI seed table. Each sends some of the table's rows to the AI assistant and stages what comes back as ordinary edits, for you to review before committing. A connection can turn this off, because it sends data — see AI assistant.

Copying and exporting

Everything you copy or export from the grid is what the grid is showing: in the order on screen, with your staged edits and new rows included, and with hidden columns left out of a copy.

Copying

  • Ctrl+C copies the selection as tab-separated text, ready to paste into a spreadsheet or back into the grid. A single cell copies its value alone.

  • Copy formatted, on a cell's right-click menu, copies values the way a Format as choice shows them — the date rather than the epoch number.

  • Copy as, on the cell and row-number menus, copies the selected rows (or the clicked row) in a format: JSON, CSV, SQL INSERTs, Markdown or HTML — and three more for working with the same rows in SQL:

    EntryCopies
    SQL VALUESThe rows as bare (…), (…) tuples, to paste into your own INSERT
    SQL UPDATEAn UPDATE per row, setting the selected columns, keyed on the table's key
    SQL WHERE INA WHERE clause that picks out exactly these rows by key
  • A column header's Copy values copies that column's values as CSV, JSON or an SQL IN list — IN (3, 7, 12), ready for a WHERE.

  • Copy the results…, on the toolbar, copies the whole result in any of the text formats.

A cell holding a tab or a line break can't survive tab-separated text — it splits into two cells or two rows when pasted. When a copy contains one, the note at the bottom of the grid says how many.

Saving to a file

Save the results to a file… on the toolbar saves the result as JSON, CSV, SQL INSERT statements, Markdown, HTML or Excel. A progress window counts the rows as they're written, has a Stop button, and stays up to say how the export ended — including anything the file couldn't hold, such as binary columns, which aren't exported as data, or an Excel cell cut to its 32,767-character limit.

Schemaic writes to name.part first and renames it at the end. If the export fails or you stop it, a file you were overwriting is left as it was, and the rows already written are in the .part file.

Both menus stay closed on a result with no rows.

Every row of a capped result

When a result was capped at the row limit and can be re-run, the save menu asks which rows first:

  • Fetched rows (N) — the rows the grid holds.
  • All rows (~N) — runs the statement again and streams every row straight to the file, however many there are, without loading them into the grid.

The All rows entry says when its file will differ from the screen: server order if you sorted by clicking a header (that sort only rearranges the rows already read), committed rows only in a Manual transaction tab (the new read can't see your uncommitted work), and without your staged edits.

To export a whole table or database without running a query first, use the schema tree's Export — see Import and dump.

Charts

The chart icon on the results toolbar (Chart the results) draws the result on screen as a bar chart, a line or a histogram. It's for a quick look at a shape — a trend, a spread, an outlier — without leaving Schemaic.

Making one

It opens as a bar chart of the last column of numbers, labelled by the first other column — the measure usually follows what it measures. Above the chart, choose:

ControlWhat it sets
ChartBar, Line or Histogram
ValuesThe column to plot — any column whose values read as numbers, DECIMAL included
LabelsThe column to label each bar or point with, or Row number

A histogram groups one column's values into ranges — up to 50 — and counts the rows in each, so it has no labels to choose.

What it shows

A chart draws the rows the grid has read, not the whole table: for a capped result, it is a chart of the first rows. The caption under it says how many rows it drew and what it left out — NULLs, and for a bar or line chart anything past the first 2,000 points.

If the result has no numeric column, the chart says so: No column of numbers to chart in this result.

Saving it

Save the chart… writes it as a PNG image or an SVG file.

Comparing results

Compare two results of the same tab row by row: what was added, what was removed, and what changed. The usual use is before-and-after — keep a result, change something, run again, and see exactly what moved.

Comparing two runs

  1. Run the query, then right-click its chip in the results strip and choose Pin.
  2. Make your change, and run the query again. The pinned result stays beside the new one.
  3. Right-click either chip and choose Compare with … and the other result.

Nothing is re-run: the comparison uses the two results as they were read. The earlier one is A and the later B, whichever chip you right-clicked, so added means added since. The ⇄ between their cards turns the comparison round.

Reading the comparison

The differences are listed in a table under the columns the two results share. The pills above it narrow it to Changed, Added or Removed rows, or show All. Changed values are blue, added rows green, removed rows red and struck through.

Match rows by decides which rows count as the same row. Schemaic starts with a column called id, or else the first column whose values are unique and never NULL on both sides. Pick another column if that's wrong, or Whole row, where nothing identifies a row: a row is then either in both results or in one, never "changed".

A few things the summary will tell you about:

  • Columns are matched by name. A column only one side has is listed, and left out.
  • Binary columns aren't compared, since the grid holds only their size.
  • If a key value appears twice on one side, only its first row is compared.
  • If either result was capped, the rows past the cap aren't compared.

Values are compared as the grid shows them, so 1 and 1.0 count as different.

Export the comparison… saves the rows on screen, under the current filter, in any of the export formats.

Schema

The schema tree is the SCHEMA panel on the left. It shows every database on the active connection, and everything in them. Show or hide it with Ctrl+Shift+E. Most of what you can do to a database object starts with a right-click on its row here.

What's in the tree

Each database opens to its tables and views, and each table opens to its columns, then its keys and indexes. Objects that aren't tables — Functions, Procedures, Sequences and the like — sit in folders after the tables. A folder only appears if it has something in it.

What you see depends on the engine:

  • Schemas appear as their own level on PostgreSQL and SQL Server, but only when there's more than one, or the only one isn't the default (public, dbo). MySQL, MariaDB and SQLite have no schema level.
  • Folders follow what the engine has: Events on MySQL; Sequences on PostgreSQL, SQL Server and MariaDB; Types, Domains and Extensions on PostgreSQL; Alias types, XML schema collections and Synonyms on SQL Server. SQLite has only tables and views.
  • Partitions nest under their table on PostgreSQL. On MySQL and SQL Server they're listed after the table's keys.
  • Triggers have no row of their own. Reach them from their table's Triggers entry, or by searching their body with Find anywhere.

A database marked Single-user — not read is in a state where reading it would take the only connection it allows. Press Read if you mean to.

Opening things

You want to…Do this
See a table's or view's rowsDouble-click it, or select it and press Enter
Jump to a column in the dataDouble-click the column
Edit a function, sequence, type…Double-click it
Expand or collapse a database/folderDouble-click it, or click its arrow

Opening a table that already has a tab switches to that tab instead of opening a second one; Open in new tab on the right-click menu forces a new one.

The tree is fully keyboard-driven: ↑/↓ move, → expands or steps into a row, ← collapses or steps out to the parent.

Finding things

There are two searches, and they answer different questions.

  • The tree's filter box (Search…, at the top of the panel) narrows the tree to names that contain what you type. A table whose column matches stays visible with that column revealed. A database or schema whose own name matches shows everything inside it.
  • Find anywhere (Ctrl+P) searches across every database at once: object and column names first, then the bodies of views, routines, triggers and events — so it finds the procedure that writes to a table, not just the table — then your snippets, open tabs and query history. Databases you've hidden are left out.

Right-click menus

Each kind of row has its own menu. The ones you'll use most:

  • Database — ER diagram, Compare with, Generate DDL, Import, Export, Back up, Create (a table, view, routine…), and housekeeping: Favourite, Colour, Hide.
  • Table — Open, Properties, Used by, Live monitor, ER diagram, Compare with, Generate (ready-made CREATE, INSERT, UPDATE and DELETE statements), Export, Copy to another database, Edit table, Triggers, Truncate, Drop.
  • View — much the same, with Edit view in place of Edit table.
  • Column, key and index rows — Copy name, Used by, and the matching Edit column, Edit index or Edit foreign key.

Every menu ends with AI explain, which asks the AI assistant to describe the object.

Two rules hold across all of them. Drop is always last and in red, and it never runs straight away: you see the SQL first. An entry that's missing means the engine can't do it; an entry that's greyed out means the connection is marked read-only.

The panel's gear menu (and a right-click on empty space) holds what isn't about one object: Refresh, Collapse all, Users and privileges, Server variables, Create database, and Show table sizes, which adds each table's size on disk to its row.

Keeping a big server tidy

  • Favourite pins a database to the top of the tree with a star.
  • Colour marks a database or table with a coloured dot. A database's colour also tints its query tabs — handy for telling production from staging at a glance — and a table's colour carries into the ER diagram.
  • Hide takes a database out of the tree and out of Find anywhere. Bring it back from the eye button at the top of the panel.
  • Refresh re-reads the whole database, even when you pick it on a single table. The tree doesn't notice changes made outside Schemaic until you do.

In this section

  • Designing a table — create a table or change one, and review the SQL first.
  • ER diagram — see how tables relate, and export the picture.
  • Live monitor — watch rows change in a table as it happens.
  • Comparing schemas — find what differs between two databases, and bring one in line.

Designing a table

The table designer creates a new table or changes an existing one. You describe the table you want; Schemaic works out the SQL to get there and shows it to you before anything runs.

Opening it

  • Change a table: right-click it in the schema tree and choose Edit table. Right-clicking a column, index or key opens the designer on that row instead — Edit column, Edit index, Edit foreign key, Edit primary key.
  • Create a table: right-click a database (or schema), then Create › Table.

A view has its own editor, under Edit view.

The tabs

TabWhat it holds
TableName and comment; on MySQL and MariaDB, the storage engine and collation too
ColumnsEach column's name, type, nullability, default, identity, comment
IndexesIndexes and unique constraints
Foreign keysReferences to other tables, with their on-delete and on-update actions
ChecksCheck constraints

Each list tab has a bar for adding, removing and reordering rows, and a form for the selected row.

A few things worth knowing:

  • Type is free text and goes to the server as written — the server decides what it means.
  • A generated column takes an expression in Generated from, and can't also have a default.
  • Indexes flagged redundant, and foreign keys with no index behind them, are advice. They never stop you from going ahead.

Reviewing and applying

When you're done, press Preview SQL. If something is missing — a table with no name, no columns — the designer says so first.

The preview shows the exact SQL that will run. From there you can:

  • Apply it to the database,
  • Copy it, or Open in editor to run it yourself later or keep it in a migration,
  • go Back to the designer to change something.

The preview also lists what depends on the table under Used by, so you can see which views or routines a change might affect before you apply it. On a read-only connection there is no Apply; the preview is still there to read and copy.

What differs between engines

Some changes can't be made with a plain ALTER TABLE on every engine. Where that's the case, Schemaic rebuilds the table: it creates a new one with the new shape, copies the rows across and swaps it in, all inside one transaction, so a failure leaves the original untouched. The preview shows every step.

  • SQLite rebuilds for most changes, since its ALTER TABLE can do very little.
  • SQL Server rebuilds to turn identity on or off, to make a column computed or plain, and to move a column.
  • PostgreSQL can't reorder columns, so there are no move arrows there.

Other engine-specific fields appear only where the engine has them: On update on MySQL; index methods on PostgreSQL; partial indexes (Only rows where) on PostgreSQL, SQLite and SQL Server; included columns on PostgreSQL and SQL Server; columnstore and XML index kinds on SQL Server.

ER diagram

The ER diagram draws tables as cards and their foreign keys as lines between them. It is for reading a schema — nothing you do in it changes the database.

Opening it

Right-click in the schema tree and choose ER diagram:

  • on a database, to see the whole database. Tables with no foreign keys at all are left out, and a chip in the toolbar counts them;
  • on a table, to see that table and the tables it links to directly.

A foreign key that points into another database shows as a small stub card.

Double-click a card to open that table.

Getting around

  • Drag a card to move it. Your arrangement is remembered for next time; the reset button (a circular arrow, at the right of the toolbar) puts everything back where Schemaic placed it.
  • Drag empty space (or drag with the middle button) to pan. The wheel scrolls up and down, Shift+wheel scrolls sideways, and Ctrl+wheel zooms around the pointer.
  • The fit button (a square frame, next to the zoom controls) zooms to show the whole diagram.
  • A wide table shows only its key columns, with a row to expand the rest.

Finding a table or column

Press Ctrl+F and type. Every match is highlighted at once, and if there's only one the diagram pans to it. Esc closes the find bar, and a second Esc closes the diagram.

Exporting

The export button in the toolbar saves the diagram as a PNG or SVG picture, or as text in Mermaid, DBML, PlantUML or Graphviz — useful for dropping into a README or a design document. The text formats can also be copied straight to the clipboard. What you export is what you see: your layout, collapsed tables and table colours included.

Live monitor

The live monitor watches one table and logs every row that is inserted, updated or deleted while it's open — whoever makes the change. It's useful for seeing what an application actually does to a table when you click a button in it.

Opening it

Right-click a table or view in the schema tree and choose Live monitor. It's also on the results toolbar when you're looking at a table's rows.

Reading the log

Each change is a row: when it was seen, what happened, and the row's values. An update shows old → new for the columns that changed; a deleted row is struck through. Newest changes are at the bottom. The pills along the top — Inserts, Updates, Deletes — filter the log to one kind, each with a count.

Controls

  • Pause polling stops checking for changes. Resume polling picks up again, and its first check shows everything that changed in between.
  • The interval picker sets how often the table is checked: every 1, 2, 5 or 10 seconds.
  • The clear button (Clear the log) empties the log, and asks first if you haven't saved it. The export button (Export the log…) saves it to a file.

Closing the monitor stops it watching, but the log is kept until you clear it.

Limits

The monitor works by reading the table repeatedly and comparing, not by hooking into the server, so it needs nothing set up on the server. That has a cost:

  • It watches the first 1,000 rows by primary key, and keeps the last 1,000 changes.
  • The table needs a key to tell rows apart. Without one, it can't track changes, and says so.
  • Large binary values are compared by length only.
  • If the table's columns change while it's watching, it starts over from that point.

Looking for running queries and sessions rather than row changes? That's the Server activity panel, which can also cancel a query or kill a session.

Comparing schemas

Schema compare shows what differs between two databases — on the same server or on different ones — and can generate the migration that brings one in line with the other.

Opening it

Right-click a database in the schema tree and choose Compare with. Then pick the other side: first a connection, then a database on it.

Choosing Compare with on a single table or view opens the same comparison, filtered to that object.

Which way it goes

The database you right-clicked is the one that will change. The one you picked is the source of truth. The header shows this with an arrow, so check it before applying anything:

  • an object only on the source-of-truth side will be created;
  • an object only on the side that changes will be dropped;
  • an object on both sides that differs will be altered to match.

Reviewing the differences

The left rail lists every object grouped by kind — tables, views, triggers, routines, sequences and more, as the engine has them — with a tally of how many differ, exist on one side only, or are identical. Select an object to see both sides' definitions next to each other. Filter by name narrows the list, and Include identical shows the objects that match as well.

Every difference that can be applied starts ticked. Untick anything you want to leave alone.

Applying

Press Preview migration. The comparison closes and the SQL for the ticked objects opens in the same preview as the table designer: Apply, Copy or Open in editor. Objects you left unticked are listed there too, so it's clear what the migration leaves as it is.

Limits

  • Both databases must be on the same kind of engine. MySQL and MariaDB compare with each other; any other mix can't be compared.
  • On MySQL and MariaDB, a trigger, routine or event body is shown but can't be ticked: the server has to give its definition again before Schemaic can recreate it safely.
  • A few differences are shown but held back from the migration, each with a note saying why — for example a table whose partitioning differs.
  • Both databases are read in full every time, so comparing a large server takes a moment.

Users and access

Users and privileges lists the accounts on a server, shows what each one may do, and lets you create, change and drop them. As with every other change in Schemaic, nothing runs until you've seen the SQL.

Opening it

Open the SCHEMA panel's gear menu, or right-click empty space in the tree, and choose Users and privileges. Accounts belong to the server rather than to any one object, so no right-click on a table or database leads here.

The database still matters: the browser reads the one your active query tab is on. PostgreSQL keeps schema and table privileges in each database separately, and a SQL Server user belongs to one database, so open a tab on the right database first.

SQLite has no user accounts, so there is no such entry on a SQLite connection.

Reading an account

The left column lists every account, with Search accounts above it. Pick one, and the right side shows its Attributes — authentication, locked, connection limit and so on, depending on the engine — and its Privileges, written out as the GRANT statements that would recreate them. Copy privileges puts all of them on the clipboard.

Accounts the server maintains itself (mysql.sys, pg_monitor and the like) are shown faint. You can read them, but Schemaic won't change or drop them.

A note under the statements says plainly what the list leaves out. The main gaps:

  • MySQL and MariaDB list what's granted to the account directly, and the roles it's in — not what those roles hold. Open the role to see that.
  • PostgreSQL lists privileges in the current database only, and leaves out EXECUTE on functions and grants on single columns. A superuser's or a predefined role's powers aren't granted, so they don't appear as statements; the note says so instead.
  • SQL Server shows DENY alongside GRANT. A login without VIEW ANY DEFINITION may be shown a short list.

The browser doesn't notice changes made from elsewhere. Press Refresh to re-read the server.

Accounts on each engine

EngineWhat's listed
MySQL and MariaDBUsers and roles. A user is a name and a host: 'app'@'%' and 'app'@'localhost' are two accounts
PostgreSQLRoles. A user is a role that can log in
SQL ServerServer logins, plus the current database's users and roles

On SQL Server the two halves do different jobs. The login holds the password and signs in to the server; the database user is what gets permissions in a database. A user mapped to a login of another name reads name ← login. With no database selected, only the logins are listed.

On Azure SQL Database the logins live in master and can't be managed from a user database, so the list holds that database's users and roles only.

Creating an account

Press New account at the foot of the list. Choose the Kind, give it a Name, and fill in what that kind needs:

  • MySQL and MariaDB — a Host. Left blank it's %, meaning any machine on the network, and the preview says so.
  • PostgreSQL — a user takes a password; a role doesn't.
  • SQL Server — a login takes a password. Leave Also a user in database ticked to create the matching user in the current database in the same step, which is usually what giving someone access takes. A user on its own is made For login an existing login, or with no login at all if you leave that empty.
  • A contained database (every Azure SQL database is one) — a user can have a password of its own, with no login behind it.
  • Microsoft Entra — when you signed in to SQL Server through Entra, a user can be made from an Entra person or group instead. Turn on Microsoft Entra; there is then no login and no password, since Entra signs it in.

Type the password twice, in Password and Confirm, then press Preview SQL. The note under the password field tells you whether the preview shows the password itself or, on PostgreSQL, a hash of it. Either way, what the preview shows is the exact statement that runs.

A MySQL or PostgreSQL user created without a password can sign in with none, and the preview warns you of it.

Changing and dropping an account

Pick the account, then use the buttons under its name:

  • Privileges — grant or revoke; see Granting and revoking.
  • Reset password — sets a new one. It isn't offered on a role, or on an account with no password of its own to change. The old password can't be recovered, so anything still configured with it stops connecting.
  • Drop — goes straight to the SQL preview. Dropping an account takes every privilege it holds with it, and they aren't recorded anywhere else. Sessions already connected as it keep running on MySQL and PostgreSQL; on SQL Server they fail at their next statement in that database. Dropping a SQL Server login leaves its database users behind, mapped to no login.

These buttons and New account are dimmed on a read-only connection, and when no database is selected — the statement has to run in one. A sentence under the buttons says which.

In this section

Granting and revoking

Select an account in Users and privileges and press Privileges. One form works in both directions: pick Grant or Revoke under Action, describe what you mean, and press Preview SQL to see the statement before it runs.

Privileges on an object

With Subject set to Privileges:

  1. Choose a Level — how far the grant reaches.
  2. Name what it applies to. The fields suggest the server's databases, schemas and tables as you type.
  3. Tick the privileges, and With grant option if the account may pass them on.

The form opens on the widest level that isn't the whole server, so a stray click can't hand out server-wide rights.

EngineLevels
MySQL and MariaDBWhole server, Database, Table
PostgreSQLDatabase, Schema, Table, Sequence
SQL ServerA login: Whole server. A user or role: Database, Schema, Table

PostgreSQL has no whole-server level. Its cluster-wide powers — superuser, creating databases, replication — are attributes of the role rather than privileges, and are changed with ALTER ROLE in the editor.

The lists cover the privileges that act on data and schema. Server-administration privileges such as MySQL's SUPER or its dynamic …_ADMIN ones, and SQL Server's rarer permissions, aren't offered; write those statements in the editor.

A grant on the whole server is spelled out in the preview for what it is: on MySQL, every database, including ones that don't exist yet; on SQL Server, the instance itself.

Membership of a role

Set Subject to Role and name the Role; the field suggests the server's roles. Granting a role gives the account everything the role holds. On MySQL, MariaDB and PostgreSQL, With admin option lets it grant the role on to others; SQL Server has no such option. For a SQL Server login the suggestions are the fixed server roles, such as sysadmin and dbcreator.

Revoking

A revoke takes away exactly what the same form would grant. To take back something you can see in the privileges list, set the form up to match that line. The preview reminds you that anything relying on the privilege fails at its next statement.

SQL Server has rules of its own, and the preview names each one when it applies:

  • A revoke always carries CASCADE, so it also takes the permission from anyone the account granted it on to.
  • A DENY beats any grant. Revoking a permission also lifts a DENY of it, which can give access back if a role the account belongs to grants it.
  • A table-level revoke also clears the account's column-level grants and denials of the same permission.
  • A table-level grant would normally erase column-level denials. Schemaic denies those columns again straight afterwards, so a column that was denied stays denied.

What the form doesn't do

  • DENY. SQL Server's denials show in the privileges list, but the form only grants and revokes. Write a DENY in the editor.
  • Column-level grants. Granting on some columns of a table — or, on MySQL and PostgreSQL, revoking such a grant — is a statement of your own.
  • Grants on a single routine, such as EXECUTE on one procedure. Write those in the editor too.

Import and dump

Getting data into a database and out of it again. Everything here starts with a right-click in the schema tree, on a database or on a table.

Which one you want

You want to…Right-clickChoose
Load a CSV, JSON or Excel file into a tablethe tableImport
Run a .sql file against a databasethe databaseImport
Write tables to a .sql file, or to CSV, JSON…database or tableExport, then a format
Take a backup with the engine's own toolthe databaseBack up
Load such a backup back inthe databaseRestore from file
Copy a table into another databasethe tableCopy to

Import means two things depending on where you click: on a table it loads a data file into that table; on a database it runs a SQL script, whose statements say for themselves which tables they touch. Export on a table opens the same window as on its database, with just that table ticked.

To save the rows of a query result rather than whole tables, use the results grid's own export — see Results grid.

Export or back up?

Both give you a file you can load again later. The difference is who writes it.

  • Export is written by Schemaic. It works the same on every engine, lets you pick tables and choose what goes in, and the .sql it writes can be loaded back with Import on a database.
  • Back up runs the engine's own tool — mysqldump, pg_dump and so on — in the terminal panel. Use it when you want the file those tools make, or when you'll restore it with them.

Read-only connections

Anything that only reads the server and writes a file on your machine is allowed on a read-only connection: Export, Back up (except on SQL Server, where the server itself writes the backup) and Copy to another connection. Import and Restore from file are greyed out.

Copying a table to another database

Right-click a table and choose Copy to. It copies the table's structure, and its rows unless you say otherwise, into another database — on this connection or another one of the same engine.

  1. Pick the connection, then the database. The chosen one shows on the Copy into button; press it to choose again.
  2. Set Schema (where the engine has them) and Name — the name starts as the table's with _copy on the end.
  3. Leave Copy data on to copy the rows; turn it off for the structure alone.
  4. Press Preview SQL. You see the CREATE TABLE first, as with any change Schemaic makes; Apply creates the table, then the rows are copied and counted as they go. Stop halts the copy, leaving the table created.

What doesn't come across: foreign keys (the tables they point at may not exist there) and triggers. A generated column's values are computed afresh, and a partitioned table arrives as one plain table. MySQL and MariaDB count as the same engine here, so you can copy between them, but nothing translates a type or option one has and the other lacks.

What differs between engines

  • Back up writes a .sql script on MySQL and MariaDB, a custom-format .dump on PostgreSQL, and a copy of the database file on SQLite. On SQL Server the server writes a .bak into its own backup folder.
  • Restore from file is offered on MySQL, MariaDB and PostgreSQL only.
  • Disable foreign-key checks in a SQL export exists on MySQL, MariaDB and SQLite; elsewhere the file adds the foreign keys after the data instead.
  • Import into a table works on all four engines. On a MySQL table whose storage engine isn't transactional (MyISAM, for one), a failed import can't be undone.

In this section

Importing a file into a table

Loads the rows of a CSV, TSV, JSON or Excel file into an existing table. The table has to exist first — create it with Create › Table if it doesn't (see Schema).

Opening it

Right-click a table in the schema tree and choose Import. It's greyed out on a read-only connection, and until the table's columns have loaded — expand it once if so.

Choosing the file

Press Choose a file…. The format is picked from the file's extension, and you can change it under Format:

FormatExtensionsNotes
CSV / TSV.csv, .tsv, .tab, .txtThe delimiter and header row are detected for you
JSON.jsonAn array of objects, or one object per line
Excel.xlsx, .xlsmOne sheet at a time — pick it under Sheet

The Reading settings change how the file is read, and the preview below follows them as you change them:

  • Delimiter and First row is a header — fix what detection got wrong.
  • Trim whitespace strips spaces around every value, inside quotes too.
  • Empty field is NULL, and Other values meaning NULL (such as NULL, \N, NA), decide which CSV values arrive as NULL rather than as text. JSON and Excel have real empty values and don't need them.

Press Next when the preview looks right.

Mapping the columns

Each column in the file is matched to a column of the table — by name when the file has a header, by position when it doesn't. Change any of them, or set one to Skip to leave it out.

Two warnings can appear here:

  • a list of table columns that aren't mapped and can't be empty — the import will fail unless the database fills them in;
  • on a MySQL or MariaDB table whose storage engine isn't transactional, a note that a failed import can't be undone.

Columns the database computes itself, such as generated columns, are never written, so a file Schemaic exported imports back cleanly.

Importing

Press Import. Schemaic first reads the whole file and checks every value against its column — numbers that aren't numbers, empty values in a column that can't be NULL, rows with the wrong number of fields. If anything is wrong, nothing is written: you get the list, with line numbers, to fix and try again. Beyond that, the database decides what it accepts.

Otherwise the rows go in inside one transaction, so a failure leaves the table as it was. Cancel while it runs rolls the import back.

Large files

A CSV is read as it goes, so its size doesn't matter. JSON and Excel files are held in memory while they load, and the window warns you when that will take a lot. An Excel workbook larger than 512 MiB isn't opened at all — save the sheet as CSV and import that instead.

Running a SQL script

Runs a .sql file — a dump, a migration, a seed script — against a database, statement by statement, with progress and a way to stop.

Opening it

Right-click a database in the schema tree and choose Import, then Choose a file…. On PostgreSQL and SQL Server you can start from a schema's row as well. It's greyed out on a read-only connection.

The script runs on the database you right-clicked, but its own statements have the last word: a USE or CREATE DATABASE in the file takes it elsewhere, and on PostgreSQL anything the file doesn't qualify goes wherever the server's search_path says — not necessarily into the schema you started from.

Before you run it

Schemaic reads the file and tells you, under What this file does:

  • how many statements of each kind it holds;
  • in red, how many destroy data — DROP, TRUNCATE, DELETE — since that can't be undone from here;
  • whether the file opens its own transaction. If it does, it lands whole or not at all; if not, a failure part-way leaves what ran before it in place. Schemaic adds no transaction of its own.

A very large file is only read in part for this summary, and the summary says so.

Running

Press Run. The window counts the statements as they go, and Stop halts the run. When it ends you see how many statements ran, or the line the failure came from and what the server said — and, either way, whether what ran before is still applied.

A .sql file from Export loads back this way.

Exporting

Writes the tables of a database to disk — either one .sql file that rebuilds them, or one file per table in CSV, JSON, Markdown, HTML or Excel.

Opening it

Right-click in the schema tree and choose Export, then a format:

  • on a database, every table in it starts ticked;
  • on a table, only that table is ticked, with the rest of the database a click away;
  • on a schema (PostgreSQL and SQL Server), the list holds only that schema's tables.

Export works on a read-only connection: it only reads the server.

Choosing tables

Tick the tables you want. Select all and None sit above the list.

A SQL export

The SQL format writes one file that recreates the tables and their rows when you run it — with Import on a database (see Running a SQL script), or any client.

OptionWhat it does
StructureCREATE TABLE, the table's triggers, and its foreign keys
DataEvery row, as INSERT statements
Other objectsTypes, sequences, routines and events the tables rely on
Drop before createDrops each table first, so the file loads onto a database that has them
One transactionWraps the load, so a failure leaves nothing behind
Disable foreign-key checksLets rows arrive in any order (MySQL, MariaDB and SQLite)

All are on to start with. Each option's note in the window says exactly what it does on your engine — read the one under Drop before create before replaying a file onto a database you care about: on every engine but SQLite it also replaces the routines in the dumped schemas.

Press Export and choose where to save. Foreign keys are added after all the data, and triggers after that, so restoring rows doesn't fire them.

The other formats

CSV, JSON, Markdown, HTML and Excel write one file per table into a folder you choose; there are no options. If any of the files already exists there, you're asked before it's replaced (Replace files).

While it runs

The footer shows which table is being written and how many rows so far. Stop cancels the export; a file it was replacing is left as it was, and what had been written is kept beside it under another name, which the footer gives. When it's done, the footer says how many tables were written — and names anything that didn't make it, such as a table that disappeared since you ticked it, or binary columns a text format couldn't hold.

Back up and restore

Back up and Restore from file run the database engine's own tools, in the terminal panel, signed in as your connection. You watch the tool's own output there, and Ctrl+C stops it.

What you need installed

The tools are looked up on your PATH. If one isn't found, the terminal panel says which.

EngineBack upRestore
MySQL and MariaDBmariadb-dump or mysqldumpmariadb or mysql
PostgreSQLpg_dumppg_restore, or psql for a .sql file
SQL Serversqlcmdnot offered
SQLitenothing — Schemaic copies the file itselfnot offered

The MariaDB names are tried first; on many Linux systems mysqldump and mysql are really MariaDB's tools under another name.

Your password goes to the tool privately, never on its command line. Over an SSH tunnel the tool connects through the tunnel. Connections that sign in with an AWS or Google Cloud IAM token can't be handed to these tools.

Backing up

Right-click a database and choose Back up, then pick where to save. The file name starts as the database's name and the date and time.

  • MySQL and MariaDB — a .sql script of one consistent snapshot, with routines, triggers and events.
  • PostgreSQL — a custom-format .dump, which pg_restore can restore from selectively.
  • SQLite — a copy of the database file, which you can open as a connection of its own.
  • SQL Server — there's no file dialog. The server writes a .bak into its own default backup folder, as a copy-only backup that leaves your scheduled backup chain alone. A second backup of the same database within the same minute replaces the first. Since this one is written by the server, it's greyed out on a read-only connection.

Restoring

Right-click a database, choose Restore from file and pick the file. You're asked to confirm first — what a restore creates or replaces can't be undone. It's greyed out on a read-only connection.

On PostgreSQL a .sql file runs through psql, stopping at the first error; anything else goes to pg_restore, skipping ownership, since the roles a dump names may not exist on this server.

A script is read before anything runs. If it switches to another database part-way — a USE or \connect line — the restore is refused, because it would write there instead of into the database you picked. Restore it into the database it names, or remove those lines from a copy.

Schemaic can't see how a restore ends: check the terminal panel for the tool's result.

AI assistant

The AI assistant answers questions about your database in a panel beside the editor. Schemaic doesn't ship a model of its own: it drives an agent CLI you already have installed and signed in to, and hands it a small set of database tools. Show or hide the panel with Ctrl+Shift+A.

The assistant is off on a new install. While it's off, nothing is sent anywhere, no agent process starts, and no AI entry appears in any menu.

Setting it up

Open the AI assistant section of Settings, or press the gear (AI settings) at the top of the panel.

SettingWhat it does
Agent CLIWhich CLI to drive: Claude Code, Codex, Antigravity, OpenCode, GitHub Copilot or Cursor. Disabled turns the assistant off.
CLI pathWhere the CLI lives. Leave it empty and Schemaic finds it on its own, and shows the path it found.
ModelAny model id the CLI accepts. Empty uses the CLI's own default. The buttons under it are shortcuts, not the whole list.
EffortHow hard the model thinks. Only shown for CLIs that take it — Claude Code, Antigravity and OpenCode — with that CLI's own levels.
Custom instructionsYour house rules, sent with every question: naming conventions, the dialect quirks you care about.
Schema contextHow much of the database's structure goes with every message — see below.

You sign in to the CLI itself, the way you normally would. Schemaic stores no API key.

Under Agent CLI a note says how tightly that CLI can be restricted. Claude Code, OpenCode and GitHub Copilot can be kept to Schemaic's tools alone. Codex and Antigravity run in a sandbox: their own tools can read files on your machine but not write them or run commands. Cursor is held back by a permissions file instead of a sandbox. Antigravity and Cursor also bring along any MCP servers you've registered with them yourself, which Schemaic can't switch off.

Schema context

  • Active database only (the default) sends an outline of the database you're working in: tables, columns, keys.
  • All databases sends the outline of every database on the connection. On a big server this can make each message large.
  • None sends no outline, and also takes away the schema tools, so the assistant has to ask you for table and column names.

Databases you've hidden in the schema tree are left out of the outline.

How much data the assistant may see is a separate choice, made per connection. That's Data access.

Asking questions

Type in the panel and press Enter. Along with your question, the assistant gets:

  • the schema outline your Schema context allows,
  • the SQL in the active editor tab — or only the selected part, if you've selected something,
  • the shape of that tab's last result: column names and types, row count, and the error if the run failed. Never the rows themselves.

The conversation is kept per connection and comes back when you reopen Schemaic. New chat starts over.

What it can do

On its own, the assistant can look things up with Schemaic's tools:

  • List and search — the databases, their tables and columns, and objects by part of a name.
  • Describe a table — its full definition, indexes and foreign keys.
  • Run a query — one read-only statement, if the connection's data access allows it. Results are capped at 200 rows, and long values are cut short.
  • Explain a query — the plan, without running it, under the same data access rule.
  • Check a table change — it can work out the SQL for a change it wants to suggest, without running anything.

None of these tools can change the database. How that's enforced is under Data access.

Acting on an answer

SQL in a reply comes with buttons:

  • Copy puts it on the clipboard.
  • Insert opens it in a new editor tab.
  • Run opens it in a new tab and runs it there, so what ran stays on screen. It goes through the same checks as anything you run yourself: a write asks first, and a read-only connection refuses it.

When the assistant suggests changing a table, the reply shows a card instead of a script. Press Review change… to open the change preview, where you see the exact SQL and apply it yourself — the same preview the table designer uses.

Elsewhere in the app

The assistant isn't only the panel. These all use the same CLI and the same data access rules:

  • AI explain at the end of every schema tree menu describes the object in the panel.
  • In the editor, Ctrl+K asks for SQL right where the caret is, and the right-click menu has Ask AI, Explain and Optimise.
  • When a query fails, the error has AI fix (a corrected statement, shown as a change you approve) and Explain (what went wrong, in the panel).
  • In the results grid: AI summary of a selection, Attach 3 rows to chat (the count follows your selection), and AI fill value, AI insert row and AI seed table for generating data.

Using Schemaic from other agents

The same tools are available to any MCP client — another agent, an editor, a desktop chat app — through schemaic mcp. It serves one saved connection over stdin and stdout:

schemaic mcp -c "Shop (prod)"

The connection needs CLI access turned on in its settings, and its AI data access level applies here too, with one difference: there's no grid to attach rows from, so rows are sent only at Let it read data. The tool that proposes table changes is left out, since there's no preview on the other end to review one. Setup for particular clients is in Command line.

In this section

  • Data access — what each level lets leave your machine, and how queries are kept read-only.

Data access

Whatever the assistant reads goes to whichever service your agent CLI talks to. Each connection decides how much of its data that can include. Structure — names, types, definitions — goes at every level; rows are what the levels are about.

Set it in the connection's settings, under AI data access. The AI assistant section of Settings shows the active connection's level, but doesn't change it. It's per connection on purpose: a scratch database on your laptop and a client's production server deserve different answers.

The levels

LevelRows that can leave your machine
Schema onlyNone. The assistant can't query or sample, and attaching rows is refused.
Only what I attachOnly rows you hand over yourself. This is the default.
Let it read dataWhatever the assistant chooses to read, as well as what you attach.

In more detail:

  • Schema only — the assistant sees structure and nothing else. Table definitions are sent in full, so column defaults, comments, check expressions and a view's whole body are included: those are definitions, not rows. In the results grid, the AI actions are replaced by a note saying they're off for this connection.
  • Only what I attach — the assistant can't read rows by itself. Rows reach it only when you send them: Attach 3 rows to chat in the grid, or AI summary of a selection. The gesture is the consent, and it covers what you selected and nothing more.
  • Let it read data — the assistant can run read-only queries, read sample rows, and see a few example rows when it describes a table. AI fill value, AI insert row and AI seed table also send up to 20 of the table's rows, newest by primary key, as examples to match.

There's no masking level. A model can't tell a masked value from a real one, so it would reason confidently about made-up data. Either the rows go or they don't.

Error messages

Database errors often quote a value back: Duplicate entry 'alice@example.com' for key 'users.email'. Below Let it read data, Schemaic replaces the quoted value with <redacted> before the message goes to the assistant — for AI fix, Explain, and a failed result in the panel. The constraint, column and kind of error still go, since they're what make the error fixable.

What always goes

Whatever the level, a message carries your question, your Custom instructions, the schema outline your Schema context allows, the SQL in the active tab (or your selection), and the column names and row count of its last result. It also carries the earlier turns of the conversation — except at Schema only, where only your own earlier messages are replayed.

How queries stay read-only

The assistant's queries are refused if they could write, whatever the connection's own Read-only setting says:

  • The statement has to be a single read: it must start with one of the engine's read-only statements (SELECT, WITH, SHOW and so on), and anything that could write is turned away before it reaches the server. On PostgreSQL and SQL Server, the functions a query may call are checked against a list as well.
  • It then runs in a read-only session, so a query that's spelled like a read but writes anyway — a SELECT of a function that deletes rows — is refused by the server.
  • SQL Server has no read-only session, so there the query runs inside a transaction that's always rolled back. A procedure that reaches outside the database, such as sending mail, can still have that effect. For a hard guarantee there, connect with a login that can only read.

This guards against mistakes and keeps the assistant from writing. It isn't a defence against a database whose owner is out to trick you: table names, comments and values are text someone else may have written, and the assistant is told to treat them as data, not instructions.

Changes the assistant suggests never run on their own. A table change comes back as a card you open in the change preview, and SQL in a reply runs only when you press Run, under the same checks as anything you run yourself.

Command line

The schemaic command runs SQL against your saved connections without opening the window. It never takes a credential: the connection comes from your saved list and its password from the OS keyring, so a script, a cron job or an AI agent can be handed a connection name instead of a password.

schemaic list
schemaic tables -c prod -d shop
schemaic query "SELECT * FROM orders LIMIT 5" -c prod -d shop --format json
schemaic exec "UPDATE orders SET state = 'sent' WHERE id = 7" -c prod -d shop

Setting it up

  1. Put it on your PATH. Open Settings › General and press Install on the Command line row. On Windows this adds Schemaic's folder to your user PATH; on macOS and Linux it links the command into ~/.local/bin. Open a new terminal afterwards. The Linux .deb and .rpm packages already install the command, so there the button is greyed out. Remove undoes it.
  2. Let it use a connection. Edit the connection and turn on CLI access, under Safeguards. It is off for every connection until you do, and a connection without it is refused before its password is even read.

schemaic list shows the connections the command may use; schemaic list --all shows the rest too, with a cli access column, so you can see why one you expected is missing.

Picking a connection and database

Every command that reaches a server takes -c (--connection) and, where it runs in a database, -d (--database):

  • -c takes the connection's name, ignoring case, or its id from schemaic list. #5 always means id 5, even if another connection is named 5. A name that matches two connections is refused, not guessed — use the id. Scripts should prefer the id: it never changes when you rename the connection.
  • -d defaults to the connection's own database. schemaic databases -c prod lists the names it takes.
  • SCHEMAIC_CONNECTION and SCHEMAIC_DATABASE stand in for -c and -d when set.

Where there is no keyring to read — over SSH, in a container — --password-stdin reads the password from a pipe instead: cat pw.txt | schemaic ping -c prod --password-stdin.

The commands

CommandWhat it does
listThe saved connections the command may use
databasesThe databases on a connection
pingLogs in and runs SELECT 1, to check a connection answers
tablesThe tables and views in a database
describeOne table's or view's columns: type, nullability, default and key
queryRuns one read-only statement and prints its rows
explainShows how the server would run a read, and what in the plan looks slow
exportStreams a read's whole result into a file
dumpWrites a database's tables to a .sql file that recreates them
comparePrints the SQL that would make one database's structure match another's
execRuns one statement that writes
mcpServes a connection to an AI agent over MCP
versionPrints the version

schemaic <command> --help gives every flag. Each command that waits on a server takes --timeout, in seconds: 30 by default, two minutes for compare, an hour for export and dump.

Output

Rows go to stdout and everything else — warnings, progress, the "rows were cut short" note — goes to stderr, so stdout is always safe to pipe or parse. --format picks the shape:

FormatWhat you get
tableA Markdown table with a row-count footer (the default)
jsonA JSON array of row objects
jsonlOne JSON object per line
csvRFC 4180 CSV with a header row
verticalOne name: value record per row, like mysql's \G

--no-header leaves out the column names (and the table's footer), for table and csv.

Exit codes

CodeMeaning
0It ran
2A usage error, or a connection, file or table that isn't there. Nothing was sent
3Refused: not a read, a read-only connection, no --yes, no CLI access, or a connection setting that makes it unsafe. Your statement never ran, and running it again unchanged refuses again
4The server or the connection failed. Retrying may work
5A write timed out after it was sent and may have been applied. Check before retrying
6query --fail-on-cap only: --limit cut the rows short (they were still printed)

In this section

Reading and exporting

query, explain and export only ever read. dump and compare read the database's structure and write nothing to the server. None of them asks a question first, because there is nothing to say yes to.

Giving the statement

query, explain, export and exec all take one statement, in one of three ways:

schemaic query "SELECT count(*) FROM orders" -c prod
schemaic query -f report.sql -c prod
schemaic query - -c prod < report.sql

It must be a single statement; a whole script is refused. Pass a statement that carries a password with - on stdin, so it doesn't land in your shell history. A statement can't come from stdin together with --password-stdin, since stdin has only one reader.

Only reads

These commands accept only a statement that reads, such as a SELECT, and refuse anything else with exit code 3. There is no flag to get past it, and it doesn't matter whether the connection is marked read-only: a write belongs to exec.

The check isn't only about the text. The statement also runs on a session the server itself holds read-only, so a function that writes is refused when it tries. SQL Server has no such session; there the read runs inside a transaction that is always rolled back.

query

Prints the rows, 200 at most unless you raise --limit. When the limit cuts the result short, a note says so on stderr; add --fail-on-cap to get exit code 6 as well, for a script that doesn't read stderr.

explain

schemaic explain "SELECT * FROM orders WHERE customer_id = 7" -c prod -d shop

Prints the server's plan as rows, and lists what in it looks slow — full scans, sorts, temporary tables, an index the server says is missing — on stderr. The statement is planned, never run, so the figures are the optimiser's estimates.

export

schemaic export "SELECT * FROM orders" -c prod -d shop -o orders.xlsx

Streams the whole result into a file, with no row cap. The format follows the file's extension — JSON, CSV, SQL, Markdown, HTML or Excel — or name it with --format (json, csv, sql, md, html, xlsx). The file is written as orders.xlsx.part and renamed when it's complete, so a failed export never leaves a half-written file under the real name.

dump

schemaic dump -c prod -d shop -o shop.sql
schemaic dump -c prod -d shop -t orders -t customers --data-only -o orders.sql

Writes a .sql file that recreates the database: its tables and views, their rows, and its types, sequences and routines. -t limits it to the tables you name (repeat it for more; outside the default schema, write sales.orders). --schema-only leaves out the rows; --data-only leaves out the CREATEs. It is the same dump as the app's, and progress is printed to stderr a table at a time.

compare

schemaic compare -c staging -d shop --source-connection prod --source-database shop

Prints the SQL that would make one database's structure match another's — the same comparison as the schema tree's Compare with. -c and -d name the database that would change; --source-connection and --source-database name the one it should come to match, on the same connection unless you say otherwise. -t narrows it to the tables you name, with their triggers.

Nothing is run. The script goes to stdout for you to read or save, and what it drops or leaves out is listed on stderr. Both sides must be the same engine; MySQL and MariaDB count as one.

Running writes

exec is the one command that changes data. It's a separate command rather than a flag on query, so a write is never one typo away from a read.

schemaic exec "UPDATE orders SET state = 'sent' WHERE id = 7" -c prod -d shop
schemaic exec - -c prod -d shop < change.sql

It takes one statement, given the same three ways as query. Several statements are refused rather than half-run — run them one at a time, so a failure part-way isn't something you have to piece back together.

A write prints how many rows it changed — (3 rows affected), or {"affected": 3} with --format json. A statement that returns rows prints them instead.

What it refuses, and what it asks

The command checks the statement before it connects, and there are two kinds of answer.

Refused outright — exit code 3, and no flag changes it:

  • any write on a connection marked Read-only;
  • a statement that needs a database when there is none to run in. Pass -d, or give the connection a default database.

Asked first — exit code 3 with the reason, unless you add --yes:

  • a DELETE or UPDATE with no WHERE;
  • a TRUNCATE;
  • a statement that deletes stored rows along with their table — a DROP TABLE, a DROP DATABASE or DROP SCHEMA, a CREATE OR REPLACE TABLE.

--yes answers the question; it can't lift a refusal. In particular it never lets a write through on a read-only connection — turn Read-only off in the connection's settings if you mean to write there.

An ordinary write, such as an UPDATE with a WHERE, runs without asking: typing exec is your say-so. That holds even with Confirm before running writes turned on for the editor.

When it times out

exec gives up after --timeout seconds (30 by default) and exits with code 5. The statement was already sent by then, and cancelling it doesn't undo what the server may have done — on an engine without transactions, part of it may have been applied. Check before running it again.

The write log

Every write exec runs is added to the same write log as the app's own, write_log.jsonl in the settings folder. Values in its SQL are masked unless Keep values in the write log is on in Settings › Query.

MCP server

schemaic mcp hands one saved connection to an AI agent that speaks MCP — an editor's assistant, a desktop app. It's the same server Schemaic's own AI assistant uses; you only need this command for an agent outside the app.

It isn't something you run in a terminal yourself. The agent starts it, talks to it over stdin and stdout, and stops it when it's done.

Setting it up

  1. Turn on CLI access for the connection, as for any other command — see Setting it up.
  2. Choose how much the agent may read, with AI data access in the connection's settings (see below).
  3. Add the server to your MCP client's configuration. Most clients take a block like this:
{ "mcpServers": { "prod": { "command": "schemaic", "args": ["mcp", "--connection=prod"] } } }

Add "--database=shop" to the arguments to give the tools a default database. Without one, on a server engine, the agent has to name the database in every call.

The server takes no password. It reads the connection's from the OS keyring, so nothing secret goes into the client's configuration file.

What the agent gets

Nothing the server offers writes to the database. What it can read depends on the connection's AI data access:

ToolWhat it doesOffered
list_databasesThe databases' namesAlways
list_schemaAn overview of the server, or one database in fullAlways
describe_tableOne table's definition and foreign keysAlways
search_objectsTables, views and columns by part of their nameAlways
run_queryRuns one read-only statement, 200 rows at mostLet it read data only
explainA read's plan, and what in it looks slowLet it read data only
sample_rowsThe first rows of a tableLet it read data only

Only what I attach, the default, gives an outside agent no rows at all: it has no way to attach any. run_query and explain pass the same read-only check as schemaic query, and a query is cancelled after 30 seconds.

The level is read when the server starts. If you change it, restart the server from your client.

When something is missing

The server writes a line to stderr as it starts — most clients show it in the server's log. It names the connection being served, and says why the row-reading tools are withheld or that there is no default database, with what to change. Look there first when the agent reports a tool missing.

A connection without CLI access stops the server before it starts, and the client shows it as failed. A database that's down doesn't: the agent sees the error on its first call, and can try again.

On Windows, if the client can't find schemaic, give command the full path to schemaic.com in Schemaic's install folder.

Engine differences

Schemaic works with four engines, and they don't all do the same things. Where an engine can't do something, Schemaic leaves the menu entry or field out rather than showing it greyed — so if you can't find an option, check here first.

MySQL and MariaDB are treated as one engine below; where they differ, the note says so.

At a glance

MySQL / MariaDBPostgreSQLSQLiteSQL Server
Sign-inPassword, AWS IAM, Google Cloud IAMPassword, AWS IAM, Google Cloud IAMNone — a file on this machineSQL login, Windows, Microsoft Entra
Manual transactionsYesYesNoYes, except on a read-only connection
Query plansYes, with AnalyzeYes, with AnalyzeYes, without AnalyzeYes, with Analyze
Users and privilegesYes; accounts have a hostYesNoYes; logins and database users, and DENY
Create and drop databasesYesYesNoYes
Schemas inside a databaseNoYesNoYes
Change a tableIn placeIn placeBy rebuilding it, for most changesIn place; by rebuilding it for a few
Move a columnYesNoYesYes
A failed change undoes its earlier stepsNoYesYesYes, mostly
Triggers on viewsNoYesYesYes
EventsYes———
SequencesMariaDB: listed, not editedYes—Yes
Types—Enum types, domains—Alias types, XML schema collections
Synonyms———Yes
Extensions, materialized views—Yes——
Back upmariadb-dump or mysqldumppg_dumpA copy of the fileBACKUP DATABASE, written on the server
Restore from fileYesYesNoNo
Dump to a .sql fileYesYesYesYes
Compare withMySQL or MariaDBPostgreSQLSQLiteSQL Server

Notes

Sign-in. User and password works everywhere but SQLite. AWS IAM (AWS CLI) and Google Cloud IAM (gcloud) are for MySQL and PostgreSQL running on RDS or Cloud SQL; Schemaic asks the cloud's own CLI for a token each time it connects. On SQL Server, Windows (this account) signs in as you and is offered only in the Windows build, and Microsoft Entra (Azure CLI) uses the Azure CLI's sign-in. See Connections.

Manual transactions. SQLite has transactions, but a SQLite tab can't be switched to Manual; it always runs in Auto-commit. On SQL Server, a read-only connection stays in Auto-commit too: it has nothing to commit. See Query editor.

Query plans. Analyze runs the statement to measure it, so it's offered only for a statement that doesn't write. SQLite has no measuring form, so there you get the plan alone.

Users. SQLite has no accounts — whoever can open the file can read it. A MySQL account is a name and a host ('app'@'%'). SQL Server keeps server logins and each database's users apart, and a DENY there wins over any grant. See Users and access.

Changing tables. SQLite's ALTER TABLE can do very little, so most changes rebuild the table: a new table with the new shape, the rows copied across, the old one swapped out. SQL Server rebuilds to switch identity on or off, to make a column computed or plain, and to move a column. PostgreSQL can't move a column at all. Every rebuild is in the preview before it runs. See Schema.

When a change fails halfway. On MySQL and MariaDB each CREATE, ALTER or DROP takes effect the moment it runs, so if the third statement of a change fails, the first two stay done. The other engines roll the whole change back — except for the few statements SQL Server won't run inside a transaction, which run one by one.

Smaller differences. On update for a column, and a table's storage engine, are MySQL's. A check that isn't enforced is MySQL's but not MariaDB's. Partial indexes are PostgreSQL's, SQLite's and SQL Server's. These fields appear only where they apply.

Back up and restore. On MySQL, MariaDB and PostgreSQL, Back up and Restore from file run the engine's own tools in the terminal panel, so those tools have to be installed. SQLite's copy is made inside Schemaic; to restore it, open the copy as a connection. SQL Server's backup is written by the server, into its own folder, so it's greyed out on a read-only connection, and restoring one is done on the server with SQL Server's own tools. See Import and dump.

Compare. Both sides must be the same engine; MySQL and MariaDB count as one. On MySQL and MariaDB, a trigger, routine or event that differs is shown but can't be ticked for the migration. See Schema.

Keyboard shortcuts

Every shortcut below is also listed in the app: click the question-mark icon in the top bar, just left of the settings gear (its tooltip says Keyboard shortcuts). The list there is the same as this one, grouped the same way.

On macOS, read Cmd for Ctrl — and Ctrl keeps working too. In an interface language other than English, the app writes the key names as your keyboard does.

The command palette

Ctrl+Shift+P opens the command palette: the Find anywhere box with a > already typed. Type after it to pick a command — open or save a file, format the code, switch connection, change the theme, toggle a panel and more. Where a command has a shortcut of its own, the palette shows it beside the command. Typing > into Find anywhere (Ctrl+P) does the same.

Global

KeysDoes
Ctrl+PFind anywhere
Ctrl+Shift+PCommand palette
Ctrl+TNew query tab
Ctrl+WClose query tab
Ctrl+TabNext tab
Ctrl+Shift+TabPrevious tab
Ctrl+1…9Jump to tab
Ctrl+Shift+TReopen last closed tab
Ctrl+OOpen SQL file
Ctrl+SSave SQL file
Ctrl+Shift+SSave SQL file as
Ctrl+Shift+EToggle schema panel
Ctrl+Shift+AToggle AI panel
Ctrl+`Toggle terminal

Editor

KeysDoes
Ctrl+EnterRun query
Ctrl+SpaceAutocomplete
Ctrl+KInline AI edit
Ctrl+FFind in editor
Ctrl+HFind and replace
Ctrl+GGo to line
Ctrl+Shift+\Jump to the matching bracket or BEGIN/END
Ctrl+/Toggle line comment
Ctrl+Shift+/Toggle block comment
Ctrl+Shift+UToggle case
Ctrl+Shift+JJoin lines
Ctrl+DDuplicate line / selection
Ctrl+XCut line / selection
Ctrl+Alt+LFormat code
Ctrl+Alt+Shift+LFormat statement
Ctrl+Alt+JMake single line
Alt+↑ / Alt+↓Move line up / down
Alt+EnterApply the quick fix under the caret
Tab / Shift+TabIndent / outdent
Tab / Ctrl+→Take the inline prediction (→ too, at a line's end) / its next word

Ctrl+Enter runs the statement under the caret. To run every statement in the tab, use Run in the command palette.

Results grid

KeysDoes
Ctrl+FFind in results
Ctrl+GGo to row
Ctrl+CCopy
Ctrl+VPaste as staged edits
Ctrl+ASelect all
Ctrl+Home / Ctrl+EndFirst / last cell
EnterEdit cell
Tab / Shift+TabNext / previous cell while editing
Ctrl+EnterCommit edits
DelMark row for deletion
F6Go to the results toolbar
← / →Move along the toolbar (Esc returns to the grid)

Schema tree

KeysDoes
EnterOpen the selected table, column or object
Shift+F10Context menu for the selected row

AI panel

KeysDoes
EnterSend message
Shift+EnterNew line
Ctrl+↑ / Ctrl+↓Recall previous / next prompt

Terminal

KeysDoes
Ctrl+Shift+C / Ctrl+Shift+VCopy / paste

ER diagram

KeysDoes
Ctrl+FFind in the diagram

More

  • Query editor, Results grid and Schema explain what these keys act on.
  • Arrow keys, Enter and Esc work as you'd expect almost everywhere, so they're listed only where they do something you wouldn't guess.