An Emacs database client with an interactive data browsing UI.
Supports MySQL and PostgreSQL through pure Elisp protocol packages, SQLite
through Emacs built-in sqlite-* functions, MongoDB through the external
mongodb.el native client, Redis through the external redis.el native
client, plus Oracle, SQL Server, DB2, Snowflake, Redshift, ClickHouse, DuckDB,
and generic JDBC URLs through a
lightweight JVM sidecar (clutch-jdbc-agent, Java 17+).
Architecture diagrams are in docs/architecture.md, and module ownership is recorded in PRD.md. For Org-Babel integration, install the separate ob-clutch package.
| Backend | Support level | Requirements and notes |
|---|---|---|
| MySQL | Core SQL support | Validated against MySQL 5.6, MySQL 8.0, and MariaDB 10.11 |
| PostgreSQL | Core SQL support | Functional and compatible, with less daily-use coverage than MySQL |
| SQLite | Core SQL support | Requires Emacs 29.1+ built-in sqlite-* functions; no external dependencies |
| Oracle / SQL Server | Core SQL support via JDBC | Requires Java 17+ and clutch-jdbc-agent.jar |
| DuckDB | Core SQL model, generic JDBC entry | Install the DuckDB JDBC driver and connect with a jdbc:duckdb:... URL |
| MongoDB | Basic native document support; optional SQL Interface surface | Normal connections use external mongodb.el native protocol support plus Clutch’s MongoDB Shell / MQL helper query buffers; SQL Interface endpoints use :surface sql-interface and require the JDBC driver |
| Redis | Basic key/value support | Normal connections use external redis.el native RESP support plus Clutch’s line-oriented Redis command buffers, key browsing, and type-aware value display |
| ClickHouse / Snowflake / Redshift / DB2 / generic JDBC | Basic SQL / query-first support | Useful through JDBC, with backend-specific limits around edits, transactions, and dialect behavior |
See docs/backend-support.org for the support-level policy and non-relational boundary.
- MySQL, PostgreSQL, and SQLite are supported without a sidecar process
- MySQL and PostgreSQL use pure Elisp protocol implementations
- SQLite uses Emacs 29.1+ built-in
sqlite-*functions - For native backend protocol, TLS, timeout, and connection examples, see docs/native-backends.md
- Result browser: single-page table view, fixed clickable header/status line, horizontal scrolling, row numbers, sort indicators, and right-aligned numeric columns
- Execution flow: run a region or statement, keep focus in the SQL buffer, refresh results below, and mark the last executed statement in the gutter
- SQL editing workflow: record view, foreign-key navigation, staged insert/edit/delete, SQL preview, and guarded commit
- Filtering and export: server-side
WHEREfilters, client-side fuzzy filters,ORDER BYsorting, horizontal paging, CSV/TSV/Org table copy/export, SQL INSERT/UPDATE copy/export for SQL results, and native document helper copy/export for MongoDB results - SQL intelligence: scoped table/column completion, Eldoc, object lookup, MySQL
HELPlookup, and cache-first metadata loading that avoids blocking point motion - Connection feedback: per-connection consoles, persisted console contents, auto-reconnect, explicit schema-refresh states, transaction status, and a dedicated debug buffer
- Stateful transient feedback: active auto-commit, filters, sort, copy refinement, result layout, staged mutation count, and Record field action are shown directly in their menus
- Inspection and extension: JSON/XML/BLOB value viewers, live cell viewer, per-column display overrides, and context export for external assistants
- REPL mode built on
comint-mode, withSELECTresults shown in the standard result browser instead of expanded inline in REPL history
Row identity support for staged UPDATE / DELETE:
| Backend | No-primary-key support |
|---|---|
| MySQL native | non-null unique keys; no physical row-locator fallback |
| PostgreSQL native | non-null unique keys, then ctid for ordinary heap tables |
| SQLite native | non-null unique keys, then rowid for tables not declared WITHOUT ROWID |
| Oracle JDBC | non-null unique keys, then ROWID |
| Other JDBC backends | non-null unique keys only |
Joined, grouped, derived, or otherwise ambiguous result sets remain read-only
for staged UPDATE / DELETE unless clutch can identify a single source table
and inject or read a matching row identity.
- Architecture guide — current module layers, backend/surface model, connection flow, query/object flow, and JDBC runtime diagrams.
- Interactive client guide — key bindings, result workflows, object actions, REPL, transient menus, faces, timeouts, and customization.
- Backend support levels — Core SQL, basic support, MongoDB SQL Interface, DuckDB, and Redis.
- Native backend guide — MySQL, PostgreSQL, SQLite, SSH tunnels, TLS, timeout behavior, and backend-specific examples.
- JDBC backend guide — JDBC driver setup, connection examples, Oracle notes, transaction behavior, and generic JDBC URLs.
- Org-Babel guide —
ob-clutchsetup, source block examples, header arguments, and connection caching. - JDBC agent protocol — sidecar RPC protocol and implementation notes.
- Emacs 29.1+
- MySQL 5.6+ / 8.x, PostgreSQL 12+, or SQLite 3 (via Emacs built-in)
- MariaDB 10.11 has been live-validated through the native
mysqlbackend; TLS withmysql_native_passwordhas also been live-validated; other MariaDB versions are expected to be broadly compatible but are not yet part of the regular test matrix - Java 17+ for the JDBC backend (Oracle, SQL Server, DB2, Snowflake, Redshift, ClickHouse, DuckDB)
For MySQL-family servers, core functionality (connect/query/object workflow, editing, prepared statements, and clutch UI workflows) is expected to work on MySQL 5.6+ and on compatible MariaDB releases. Some newer server-side features remain version-specific:
- MySQL 5.6 does not provide a native JSON column type
- MariaDB exposes
JSONas an alias over text withjson_valid(...)checks - MariaDB 10.11 TLS has been validated with
mysql_native_password; the oldermysql_old_passwordplugin is not supported by the native client - newer auth plugins and TLS combinations vary by server family/version
Install clutch from MELPA or another package archive:
(package-install 'clutch)Protocol packages are optional and backend-specific. clutch does not install
every database protocol package up front, because many users only use one
backend. Install the protocol package for each backend you configure:
| Backend | Extra Emacs package |
|---|---|
:backend mysql | mysql.el |
:backend pg | pg.el / pg-el |
:backend mongodb | mongodb.el |
:backend redis | redis.el |
:backend sqlite | none; Emacs 29.1+ built-in SQLite support |
:backend jdbc / Oracle / SQL Server / ClickHouse / DB2 / DuckDB | none; uses the bundled JDBC adapter |
If a configured backend’s protocol package is missing, clutch reports the
missing package when connecting. Install that package with your package manager,
ensure it is on load-path, then retry the connection; restarting Emacs is the
safest way to clear stale autoload or native-compile state after installation.
JDBC support ships inside clutch itself, but the runtime still needs Java 17+
and clutch-jdbc-agent.jar. Individual JDBC databases may also need driver
jars.
For Org-Babel support, install the separate ob-clutch package.
For source checkouts, add clutch and any native protocol backend checkout you
use to load-path explicitly:
(add-to-list 'load-path "/path/to/clutch")
(add-to-list 'load-path "/path/to/mysql.el") ; only for :backend mysql
(add-to-list 'load-path "/path/to/pg-el") ; only for :backend pg
(add-to-list 'load-path "/path/to/mongodb.el") ; only for :backend mongodb
(add-to-list 'load-path "/path/to/redis.el") ; only for :backend redis
(require 'clutch)This release separates protocol and Org-Babel packages from the main
clutch package. If you are upgrading from an older checkout that bundled
everything in one repository, this is a breaking packaging change:
- mysql.el is no longer bundled in this repository. Install it separately for
:backend mysql. - pg.el is no longer bundled in this repository. Install it separately for
:backend pg. - mongodb.el is no longer bundled in this repository. Install it separately for
:backend mongodb. - redis.el is a lazy optional protocol package. Install it separately for
:backend redis. - ob-clutch.el is no longer bundled; install
ob-clutchseparately for Org-Babel source blocks. - Saved connections must specify
:backendexplicitly.
(add-to-list 'load-path "/path/to/clutch")
(require 'clutch)
(setq clutch-connect-timeout-seconds 10
clutch-read-idle-timeout-seconds 30
clutch-query-timeout-seconds 20
clutch-jdbc-rpc-timeout-seconds 15)
(setq clutch-connection-alist
'(("dev-mysql" . (:backend mysql
:host "127.0.0.1" :port 3306
:user "root" :password "test"
:database "mydb"
:connect-timeout 5
:read-idle-timeout 60))
("dev-pg" . (:backend pg
:host "127.0.0.1" :port 5432
:user "postgres" :password "test"
:database "mydb"))
("prod-pg" . (:backend pg
:host "pg.internal" :port 5432
:user "app" :database "appdb"
:ssh-host "bastion-prod"))
("remote-pg" . (:backend pg
:host "127.0.0.1" :port 55433
:user "app" :database "appdb"
:tramp "/ssh:devbox:/workspace/"))
("dev-redis" . (:backend redis
:host "127.0.0.1" :port 6379
:database 0))
("dev-sqlite" . (:backend sqlite
:database "/path/to/my.db"))))- Every entry must specify
:backend(mysql,pg,sqlite,mongodb,redis, or a JDBC driver symbol such asoracle). - SQLite is local and file-based: only
:databaseis required; use":memory:"for a transient database. Do not combine SQLite with:ssh-host,:ssh-tunnel, or:tramp. :passwordis optional for network backends; see Password Management for auth-source integration.- Network backends accept
:connect-timeoutand:read-idle-timeout. PostgreSQL and JDBC also accept:query-timeout; JDBC additionally accepts:rpc-timeout. - TLS can be enabled with
:tls t. For explicit plaintext, prefer:ssl-mode disabledon MySQL and:sslmode disableon PostgreSQL. :ssh-hostand:trampboth create local forwards for structured:host/:portendpoints.:ssh-hostuses a~/.ssh/confighost alias, while:trampderives the origin from an ssh-like or container TRAMP directory.:tramp-default-directoryremains accepted as a longer spelling.- Query-console SQL is saved by connection identity rather than saved connection name, so renaming a saved connection keeps the same console SQL.
JDBC backends use a driver symbol as :backend. See
docs/jdbc-backend.org for supported databases and setup.
M-x clutch-query-console ;; Select a saved connection, or press RET on an
;; unmatched connection to create a temporary connection
M-x clutch-query-sqlite-file ;; Shortcut: select a SQLite file → opens a connected SQL console
;; Header-line: MySQL[root@127.0.0.1:3306/mydb]
;; or PostgreSQL[postgres@127.0.0.1:5432/mydb]
;; or SQLite[my.db]
Repeated calls with the same name switch to the existing buffer instead of
opening a new one. Use clutch-switch-console to jump between open consoles.
clutch-query-console lists saved connections; pressing RET with no matching
connection starts a temporary connection flow and opens a query console for it.
SQLite is part of that flow and asks for a database file instead of host/user
credentials. clutch-query-sqlite-file is the direct shortcut for local
SQLite files. If no saved connections are configured, clutch-query-console
starts the temporary connection flow immediately.
SELECT * FROM users LIMIT 10;Press C-c C-c to execute. If a region is selected, the selected SQL runs; otherwise the statement at point runs. Results appear in a split result buffer below.
For native MySQL and PostgreSQL, and for JDBC connections that run in manual-commit mode, clutch uses the same transaction keys:
C-c C-atoggles auto-commit when supportedC-c C-mcommitsC-c C-urolls back
SQLite does not expose these transaction controls; its console header omits the
Tx segment.
Native MySQL maps C-c C-a to the server session’s autocommit flag directly.
Native PostgreSQL uses a clutch-managed manual mode: enabling manual mode does
not send BEGIN immediately, the first foreground statement opens the
transaction lazily, and transactional DDL also counts as uncommitted work, so
toggle/disconnect stays blocked until you commit or roll back.
Connection entries may include :password, but auth-source is preferred. When
:password is omitted, clutch resolves credentials through:
- pass entries via
auth-source-pass, matching the connection name suffix or an explicit:pass-entry - standard
auth-source-searchby:host,:user, and:port - an interactive
read-passwdprompt as the final fallback
(require 'auth-source-pass)
(setq clutch-connection-alist
'(("dev-mysql" . (:backend mysql
:host "db.example.com" :port 3306
:user "alice" :database "mydb"))))pass insert mysql/dev-mysql ;; or just: pass insert dev-mysqlFor JDBC connections (including Org-Babel blocks), an explicit :pass-entry
that resolves to no password now fails fast in Emacs instead of sending a null
password to the driver. If you use pass, make sure auth-source-pass is
enabled first.
See the auth-source manual for supported credential stores.
For bastion-style access, add :ssh-host to a saved network connection:
("prod-pg" . (:backend pg
:host "pg.internal" :port 5432
:user "app" :database "appdb"
:ssh-host "bastion-prod"))Clutch opens a local SSH forward through your normal OpenSSH configuration.
Use M-x clutch-prepare-ssh-host, or S from C-c ?, when the first SSH use
needs host-key confirmation or a key passphrase. The batch tunnel itself uses
non-interactive OpenSSH auth, so load keys into ssh-agent or configure
AddKeysToAgent when needed.
Add :ssh-tunnel direct-first when the same profile should try a direct
connection before falling back to SSH. SSH forwarding applies to structured
:host / :port entries; opaque :url profiles, including JDBC and MongoDB
URLs, still need manual tunnels or backend-level transport support.
Backend-specific tunnel details live in docs/native-backends.md.
Opening a TRAMP buffer does not globally change clutch. TRAMP is considered
only when a connection is created, and the chosen origin is stored for later
reconnect, completion, refresh, and query execution. Configure :tramp when a
profile should always use a remote-machine or container endpoint:
("remote-pg" . (:backend pg
:host "127.0.0.1" :port 55433
:user "app" :database "appdb"
:tramp "/ssh:devbox:/workspace/"))Without :ssh-host or :tramp, commands invoked from a TRAMP buffer can infer
that buffer’s remote context. clutch-tramp-context-policy controls this:
nil: never infer TRAMP contextask(default): ask before using the current TRAMP contextauto: use the current TRAMP context without asking
Supported origin types, container relay requirements, and forwarding limits are documented in docs/native-backends.md.
You can also open any .sql file, enable clutch-mode, and connect
manually — the query console is not required.
1. Open a .sql file
2. M-x clutch-mode — enable clutch (inherits sql-mode syntax/fontification)
3. C-c C-e — select a saved connection or enter params manually
Mode-line shows MySQL[root@127.0.0.1:3306/mydb]
4. C-c C-c — execute region, or the current statement/query at point
In ordinary clutch-mode or REPL buffers, C-c C-e keeps that generic
connect flow: select a saved connection, or press RET with no matching
connection to enter temporary params. For SQLite files, prefer
M-x clutch-query-sqlite-file, or M-x clutch-query-console followed by RET
with no matching connection and backend sqlite; both open a connected SQL
console rather than using the database file buffer as the editor. In
query-console buffers, C-c C-e
reconnects the connection already associated with that console, without
reopening the global connection picker.
To switch to another saved or temporary connection, use M-x clutch-query-console.
For deeper troubleshooting, enable M-x clutch-debug-mode, reproduce the
failure, then inspect *clutch-debug*. Enabling the mode starts a fresh
capture window and creates that dedicated buffer automatically. It is the only
supported debug UI, and it shows problem records, generated/internal SQL when
relevant, recent redacted debug events, and JDBC stderr/debug payload when
available.
To activate clutch-mode automatically for .sql files, add to your config:
(add-to-list 'auto-mode-alist '("\\.sql\\'" . clutch-mode)).mysql files activate clutch-mode automatically without any configuration.
Detailed key bindings, result-browser workflows, object navigation, Embark integration, transient menus, faces, timeouts, and customization now live in docs/interactive-client.org.
Common entry points:
C-c C-cexecutes the region or statement at point- Standard completion completes SQL identifiers at point, including empty
column positions;
C-c TABinvokes it explicitly M-.jumps SQL aliases to their statement definition; object lookup usesC-c C-d/C-c C-jC-c ?opens the transient menu- Stateful transient entries highlight their current choice; unavailable actions stay visible but inapt when their surrounding context is still useful
C-c C-jstarts the object workflowRETopens record view from a result row- Pressing
scycles sorting for the result column at point; simple table results use server-sideORDER BY, while UNION, grouped, derived, and other non-rewritable results sort the current page locally. UseCto jump to another visible column first, or click a result header to cycle it i,d, andC-c C-cstage and commit row changes in result buffersC-c 'edits the current result cell; in that edit buffer,C-c C-nstages databaseNULLM-x clutch-copy-context-for-agentcopies SQL, table metadata, and the latest matching visible result sample as Markdown for an external agent; the same command is available askin the main and result transients. Table metadata reuses the existing object describe path.
MongoDB is basic native document support through mongodb.el: ordinary MongoDB
deployments, supported MongoDB Shell / MQL helper commands, and shared
object/result workflows. It is not a full mongosh JavaScript runtime.
MongoDB SQL Interface stays on the same mongodb backend as
:surface sql-interface and requires the JDBC sidecar plus MongoDB JDBC driver
jar. See docs/mongodb-backend.org.
Redis is basic key/value support through redis.el. It connects to ordinary
Redis TCP endpoints, uses line-oriented clutch-redis-mode command buffers,
and maps key browsing/type-aware reads into the shared Clutch grid. Redis
support is intentionally basic: no SQL row editing, joins, row identity,
transaction workflow, pub/sub loops, cluster management, or stream consumer
workflows. See docs/backend-support.org and
docs/native-backends.md for support boundaries.
JDBC support covers Oracle, SQL Server, DB2, Snowflake, Redshift, ClickHouse, MongoDB SQL Interface, DuckDB, and generic JDBC URLs through the clutch-jdbc-agent sidecar. For setup, driver installation, connection examples, backend-specific notes, and transaction behavior, see docs/jdbc-backend.org.
For the sidecar wire protocol and agent internals, see docs/jdbc-agent-protocol.md.
Org-Babel integration lives in the separate ob-clutch package and supports saved clutch connections plus MySQL, PostgreSQL, SQLite, and generic JDBC-backed clutch source blocks. For setup, block examples, header arguments, and connection caching, see docs/org-babel.org.
Timeouts can be configured globally or per connection, and long-running queries can be interrupted with C-g. Backend-specific cancel behavior, debug workflow, result displayers, schema warmup, CSV encoding, and completion customization are documented in docs/interactive-client.org.
For mysql, pg, and SQLite connection examples, TLS notes, timeout
behavior, and helper APIs, see docs/native-backends.md.
The non-live CI gate used by GitHub Actions can be run locally:
./test/run-ci.sh allDefault ERT runs intentionally skip live tests when database credentials are not set. Treat those runs as unit/regression coverage, not proof that real database workflows still work. External protocol packages and the Org-Babel bridge live in separate repositories and carry their own focused test suites.
./test/run-ci.sh native-liveThe native live runner starts or reuses local containers and covers MySQL,
PostgreSQL, and ordinary MongoDB native protocol connections against real
databases. Other JDBC live suites remain environment-driven and are skipped by
default. MongoDB SQL Interface JDBC live tests require a SQL Interface
endpoint; ordinary MongoDB work uses the default mongodb document surface.
Contributor release gates are
listed in AGENTS.md §Pre-Commit Checklist.
- AST-based SQL rewriting is deferred, not planned as a near-term feature. The current top-level clause scanner, direct LIMIT/OFFSET pagination, and conservative result capability checks cover known WHERE/filter/count/ pagination cases without making derived-table wrapping the default escape hatch. Revisit a full parser only if concrete rewrite bugs or optimization features justify the added complexity.
GPL-3.0-or-later. See LICENSE.
