Fast, lightweight desktop client for MySQL, MariaDB, PostgreSQL, SQL Server, ClickHouse, SQLite, Redis and Valkey in the spirit of DataGrip. macOS, Windows and Linux.
Built with Tauri 2 (Rust: mysql_async, tokio-postgres, tiberius, rusqlite, the ClickHouse HTTP interface,
redis) and React 19 / TypeScript, CodeMirror 6 and a virtualized grid.
The binary is small, it starts in well under a second, and it uses a fraction of the memory of Electron-based tools.
See docs/ARCHITECTURE.md for the design.
QueryCraft is under active development. Expect rough edges and please report them.
- Eight engines — MySQL, MariaDB, PostgreSQL, SQL Server, ClickHouse, SQLite, Redis and Valkey, each with its own icon in the explorer. The SQL engines share a schema-aware SQL editor with per-dialect identifier quoting; Redis and Valkey get their own key-value console instead (see The Redis/Valkey console). See Engine notes for what differs.
- Connections — create, test and edit connections; passwords are stored in the system keyring
(Keychain, Credential Manager, Secret Service), never in plain-text files. SQLite connections point at
a file (or
:memory:). - SSL/TLS — the server certificate is verified against the system trust store by default; an extra CA certificate file (PEM) can be added for private CAs, and verification can be switched off for self-signed certificates on a trusted network.
- SSH tunnel — as in DataGrip's SSH/SSL tab: reach the database through an SSH host with a password,
a private key (optionally with a passphrase) or the running OpenSSH agent. Host keys are checked against
~/.ssh/known_hostslikeStrictHostKeyChecking=accept-new: a new host is recorded, a changed key is refused. The SSH password or passphrase follows the "Save password" setting. - Database explorer — databases (schemas for PostgreSQL) → tables and views → columns, indexes,
foreign keys; for Redis/Valkey, databases 0–15 → keys, loaded with
SCANand filterable by pattern. SQL Server tables carry their schema in the name (schema.table, e.g.dbo.Orders) and are qualified as"db"."schema"."table"in generated SQL. Lazy loading, filtering, context menus, keyboard navigation. - SQL console — syntax highlighting and schema-aware autocomplete in the engine's dialect; run the statement under the cursor, the selection or the whole script; cancel running queries; multiple result sets with timings. Redis/Valkey connections get a dedicated command console instead — see The Redis/Valkey console.
- Session per tab — every console and data tab owns its own connection, so
USE, transactions and temporary tables stay scoped to the tab, exactly like DataGrip. - Results grid — row and column virtualization, sorting, resizable columns, DataGrip-style selection
(drag, Shift+click, Shift+arrows, row and column selection, select all), copy as TSV/CSV with or without
headers, export to CSV / JSON / Excel files or copy as TSV / SQL
INSERT. The row limit only applies to the grid: a file export of a truncated result re-runs the statement without the limit and writes every row, and clicking the500+ rowscount in the footer runsSELECT COUNT(*)over the statement to show the total. - Table data editing —
WHEREfilter with column and keyword suggestions, sorting, pagination, inline cell editing, add and delete rows, deferred Submit / Revert applied in a single transaction, SQL preview. - Clipboard paste into the grid: each line becomes a row, missing rows are added, tab /
;/,/|split values across columns,NULLand empty cells become SQL NULL; a single value fills a selected range. - DDL view —
SHOW CREATE TABLE(synthesized from the catalog for PostgreSQL) with highlighting. - Themes — system (follows the OS and switches live), light and dark.
- Native menu and DataGrip keymap (see below); settings dialog for theme, row limit, editor font size and updates.
- Automatic updates — new releases are downloaded from GitHub at startup and applied after a restart (see Updates).
- AI assistant — bring your own API key to generate SQL from a description, fix a failing statement, explain or optimize a query, or chat about the current database, right from the console (see AI assistant).
Shortcuts follow the DataGrip defaults for each platform.
| Action | macOS | Windows / Linux |
|---|---|---|
| Execute statement / selection | ⌘⏎ | Ctrl+Enter |
| Execute whole script | ⇧⌘⏎ | Ctrl+Shift+Enter |
| Cancel running query | ⌘F2 | Ctrl+F2 |
| New query console | ⌃⇧Q | Ctrl+Shift+Q |
| Refresh explorer / reload page | ⌘R | Ctrl+F5 |
| Submit changes | ⌘⏎ | Ctrl+Enter |
| Revert changes | ⌥⌘Z | Ctrl+Alt+Z |
| Add row | ⌘N | Alt+Insert |
| Delete / restore selected rows | ⌘⌫, or ⌫ / Delete in the grid | Ctrl+Y, or Delete / Backspace in the grid |
| Set NULL | ⌥⌘N | Ctrl+Alt+N |
| Next / previous page | ⌥⌘↓ / ⌥⌘↑ | Ctrl+Alt+↓ / Ctrl+Alt+↑ |
| Open table data (explorer) | F4 | F4 |
| Go to DDL (explorer) | ⌘B | Ctrl+B |
| Database explorer | ⌘1 | Alt+1 |
| Close tab | ⌘W | Ctrl+F4 |
| Next / previous tab | ⇧⌘] / ⇧⌘[ | Alt+→ / Alt+← |
| Settings | ⌘, | Ctrl+Alt+S |
| Generate SQL with AI | ⌘\ | Ctrl+\ |
| AI chat | ⇧⌘I | Ctrl+Shift+I |
| Copy selection (TSV) | ⌘C | Ctrl+C |
| Paste into grid | ⌘V | Ctrl+V |
| Select all cells | ⌘A | Ctrl+A |
In the SQL editor: duplicate line or selection ⌘D / Ctrl+D, delete line ⌘⌫ / Ctrl+Y, move line ⌥⇧↑ / ⌥⇧↓, toggle line comment ⌘/ / Ctrl+/, find ⌘F / Ctrl+F.
The keymap lives in src/lib/keymap.ts.
| MySQL / MariaDB | PostgreSQL | SQL Server | ClickHouse | SQLite | Redis / Valkey | |
|---|---|---|---|---|---|---|
| Transport | mysql_async (native protocol, TLS) |
tokio-postgres (TLS) |
tiberius (TDS, TLS via rustls) |
HTTP interface (reqwest), port 8123 |
rusqlite (bundled SQLite) |
redis crate (RESP, TLS) |
| Explorer level under the connection | databases | schemas of the connected database | databases | databases | main and attached databases |
databases 0–15 (keys) |
| Session per tab | dedicated connection, USE db |
dedicated connection, search_path |
dedicated connection, USE db |
HTTP session_id + database |
dedicated connection | dedicated connection, SELECT db |
| Cancel | KILL QUERY |
cancel request | KILL <spid> |
KILL QUERY WHERE query_id = … |
sqlite3_interrupt |
CLIENT KILL ID |
| SSH tunnel | yes | yes | yes | yes | no (local file) | yes |
| Grid editing | by primary key | by primary key | by primary key | read-only | by primary key | key values (by type) |
| DDL | SHOW CREATE TABLE |
synthesized from the catalog | synthesized from the catalog | SHOW CREATE TABLE |
sqlite_master.sql |
n/a |
PostgreSQL results are fetched with the simple query protocol (every value arrives as text and is typed by
the prepared statement's description), so a console SELECT without LIMIT is buffered before the row
limit is applied. ClickHouse has no row-level UPDATE/DELETE, so its data tabs are read-only. SQL Server
has no LIMIT/OFFSET; table data paging uses OFFSET … ROWS FETCH NEXT … ROWS ONLY, which requires an
ORDER BY (a page without an explicit sort falls back to ORDER BY (SELECT NULL)). SQL Server is the one
backend on rustls rather than native-tls: SQL Server always TLS-wraps its login packet, and on macOS
native-tls (the system Security framework) cannot complete that handshake at all.
Redis and Valkey connections speak commands, not SQL: the console runs one command per line in
redis-cli syntax (SET "my key" "a value", "…" with backslash escapes or '…', # lines are
comments). Cmd/Ctrl+Enter runs the command on the cursor's line; Cmd/Ctrl+Shift+Enter runs every line
in the console top to bottom. Results are shown as an ordinary grid: HGETALL returns field/value
rows, ZRANGE … WITHSCORES returns member/score, SCAN returns the next cursor and the matching
keys. The editor highlights the ~120 built-in commands and completes them, plus key names for the
current database. SUBSCRIBE/PSUBSCRIBE and MONITOR are refused in the console — they never
return, which does not fit a request/response query tab.
The explorer lists databases 0–15 under a Redis/Valkey connection; expanding one loads its keys with
SCAN (first 1,000, marked 1,000+ when there are more). The filter box becomes a server-side MATCH
pattern instead of filtering the already-loaded list, so it works for a database with far more keys than
fit in the tree. Double-clicking a key opens its own tab with the full value in a grid shaped by the
key's type: a string is one value cell, a hash is field/value rows, a list is index/element
rows (the index is read-only), a set is member rows, a sorted set is member/score rows, and a
stream is its id/entry rows shown read-only. Cells can be edited, rows added or deleted (not for
strings or streams); Submit sends every pending change as one batch of commands that runs atomically
(Redis MULTI/EXEC), Revert discards them. The tab also has its own TTL control (set an expiry in
seconds, or clear it with Persist) and a two-click "Delete key". The context menu's "Open in console"
runs the same type-based preview command as a plain query instead, for a quick read-only look.
TLS connections to Redis/Valkey verify the server certificate against the system trust store only: the
redis crate's native-TLS backend cannot load an extra CA certificate file, so for a private CA either
add it to the system trust store or turn certificate verification off for that connection.
QueryCraft ships a bring-your-own-key (BYOK) AI assistant: generating a SQL statement from a plain-language description, fixing a statement that just failed, explaining or optimizing a query, and a side chat for open-ended questions about the current database. There is no bundled service and no telemetry — every request goes straight from your machine to the provider you chose, using your own API key.
Providers — Anthropic, OpenAI, Google Gemini, OpenRouter, DeepSeek, Mistral, a local Ollama or LM
Studio server (no key needed), or any other OpenAI-compatible endpoint. Configure one in Settings →
AI (Cmd+, / Ctrl+Alt+S): pick a provider, paste an API key (pasting a recognized key format
switches to the matching provider automatically), choose a model and, for local/custom providers, a
base URL. API keys are stored in the system keyring (Keychain, Credential Manager, Secret Service),
never in a plain-text file, and never sent anywhere except the provider's own API.
Generate SQL — in a SQL console, click ✦ AI in the toolbar or press Cmd+\ / Ctrl+\ to open
the assist bar. With no selection, describe the query you need and it is inserted at the cursor; with
a SQL selection, describe how it should change and the selection is rewritten. The answer streams in
as a read-only preview; Accept applies it as a single undoable edit, Copy copies it, Regenerate
asks again, and the input stays open for a follow-up refinement. A statement that would DROP,
TRUNCATE, or DELETE/UPDATE without a WHERE clause is flagged before you accept it.
Fix with AI — a failed statement's result shows a ✦ Fix with AI button that opens the same bar already working on a fix, using the statement and the error message.
Explain / Optimize query — the ✦ AI toolbar button is a split button: its caret opens Explain
query and Optimize query alongside Generate SQL and Open AI chat. Both act on the current
selection, or the statement at the cursor, and answer in the AI chat panel (they produce prose plus
SQL, which does not fit the single-statement assist bar). Explain query asks for a plain-language
walkthrough of what the statement does. Optimize query first runs the dialect's EXPLAIN for the
statement — never EXPLAIN ANALYZE and never the statement itself — then asks for a performance review
grounded in that plan, including index suggestions; a busy indicator shows on the menu item while
EXPLAIN runs. Engines with no usable EXPLAIN (SQL Server, Redis, Valkey) get a review without a
plan instead.
AI chat — a side panel for open-ended questions about the current connection: toggle it with the
✦ Chat toolbar button, Shift+Cmd+I / Ctrl+Shift+I, or AI → AI Chat. Its context (and its own
conversation) follows the active tab's connection and database, or the explorer selection when no tab
is open; New chat clears the current context's conversation. Answers render as Markdown — code
blocks get Copy and, for SQL/Redis, Insert (into the active console at the cursor, or a new
console if none is open for that connection). The "Include current query" chip attaches the active
console's statement at the cursor/selection to your message. Conversations are kept in memory only —
never written to disk, and gone when you close the app.
Per-connection access level — each connection's AI assistant setting (in its General tab)
controls what the assistant may see for that connection: Query and schema sends the query text and
the schema of the tables involved (names, columns, types, keys, comments — never row data); Query
only sends just the query/error text with no schema; Off disables the assistant entirely for that
connection. Optimize query's EXPLAIN plan is sent even at Query only — it describes how the engine
would run the statement, not row data.
Inline suggestions — off by default, since every pause while typing sends a request to the
provider. Turn it on in Settings → AI ("Suggest completions while typing") and, optionally, pick a
separate (ideally smaller and faster) model just for it. While enabled, pausing in a SQL console shows
a completion as dimmed ghost text at the cursor: Tab accepts it, Esc dismisses it, and typing
anything just clears it. It respects the connection's access level the same way as the rest of the
assistant, and is unavailable for Redis/Valkey consoles and where the assistant is off.
Download the installer for your platform from the
Releases page (.dmg for macOS on Apple Silicon and Intel,
.msi / .exe for Windows, .AppImage / .deb / .rpm for Linux), or build from source as described below.
The binaries are not code-signed or notarized yet, so both macOS and Windows warn before the first launch.
Apple has not notarized the app, so Gatekeeper refuses it after the download. Copy QueryCraft.app to
Applications, then run this command once in Terminal to clear the quarantine flag:
xattr -dr com.apple.quarantine /Applications/QueryCraft.appAfter that the app opens normally. Repeat the command after installing a new version.
SmartScreen shows a warning for the installer: choose More info → Run anyway.
At startup QueryCraft checks the latest GitHub release and, if it is newer, downloads it in the background:
on macOS and Linux (AppImage) the new version is installed at once and starts at the next launch, on Windows
the installer runs when you agree to restart. A notification with a Restart button appears when the update
is ready; Help → Check for Updates… (or Check now in Settings) runs the check by hand. The startup check
can be switched off in Settings (Check for updates at startup and install them automatically). Every update
is verified against the public key embedded in the app before it is installed. Installations from .deb /
.rpm are left to the package manager: the app only shows a short notice with a link to the new release.
Requirements: Rust (stable), Node.js 20+, pnpm and the Tauri system dependencies.
pnpm install
pnpm tauri dev # run the desktop app with hot reload
pnpm tauri build # build the installer for the current OS
pnpm test # frontend unit tests (vitest)
pnpm typecheck # tsc --noEmit
pnpm lint # biome (lint + format check); pnpm lint:fix applies fixes
cd src-tauri && cargo test # backend unit testsThe UI can be developed in a regular browser without Tauri: run pnpm dev and open http://localhost:1420 —
IPC commands are served by a mock (src/api/mock.ts) with sample connections and data.
Development builds keep connection passwords in secrets.dev.json next to connections.json in the app's
config directory instead of the system keyring: the keyring grants access per code signature, and every
rebuild would ask for the keychain password again. Set QUERYCRAFT_KEYRING=1 to use the keyring in a
development build; release builds always do.
Backend integration tests against live servers are skipped unless the DSN is provided
(host:port:user:password); the SQLite suite needs nothing and always runs:
cd src-tauri
QUERYCRAFT_TEST_DSN="127.0.0.1:33070:root:secret" cargo test --test live_mysql
QUERYCRAFT_TEST_PG_DSN="127.0.0.1:33071:postgres:secret" cargo test --test live_postgres
QUERYCRAFT_TEST_CH_DSN="127.0.0.1:33072:default:secret" cargo test --test live_clickhouse
cargo test --test sqliteThrowaway servers for development on those ports (MySQL 33070, PostgreSQL 33071, ClickHouse 33072,
MariaDB 33073; password secret, database shop) are defined in docker-compose.yml:
docker compose up -d # or: docker compose up -d postgresThe TLS suite expects servers with a self-signed certificate (scripts/tls-servers.sh starts them,
ClickHouse HTTPS on 33074) and checks that connections are encrypted, that certificate verification
rejects the untrusted certificate and that the generated CA file makes it pass. The SSH suite needs the
OpenSSH container from scripts/ssh-server.sh (port 33075, joined with the database containers on a
docker network) and covers password, key, passphrase and agent authentication, changed host keys and
TLS verification through the tunnel:
scripts/tls-servers.sh && scripts/ssh-server.sh
cd src-tauri
QUERYCRAFT_TEST_TLS=1 cargo test --test live_tls
QUERYCRAFT_TEST_SSH=1 cargo test --test live_ssh
# agent authentication: load the test key into an agent first
ssh-add "${TMPDIR:-/tmp}/querycraft-ssh/id_ed25519" && QUERYCRAFT_TEST_SSH=1 QUERYCRAFT_TEST_SSH_AGENT=1 cargo test --test live_sshApplication icons are generated from src/assets/logo-icon.svg with pnpm icons (requires rsvg-convert).
Release builds sign the updater artifacts with a minisign key: the
public key lives in src-tauri/tauri.conf.json (plugins.updater.pubkey), the private key is the
TAURI_SIGNING_PRIVATE_KEY repository secret (plus TAURI_SIGNING_PRIVATE_KEY_PASSWORD) used by
release.yml, which also uploads the latest.json manifest the app polls. A local pnpm tauri build
needs the same variables (pnpm tauri signer generate -w ~/.tauri/querycraft.key creates a new pair, but
apps built with the old public key cannot verify updates signed with a new one).
src-tauri/ Rust backend: Tauri commands, native menu, engine drivers, SQL execution, schema metadata
src/ React frontend: api (IPC contract), store (zustand), lib (pure functions + tests), components
docs/ Architecture notes and README screenshots
Contributions are welcome — please read CONTRIBUTING.md first. This project follows a Code of Conduct.
QueryCraft is released under the Apache License 2.0.