Dadbod Grip turns database tables into editable Vim buffers, with schema browsing, staged mutations, generated SQL, relationship navigation, and cross-database federation inside Neovim.

Grid row edits stage before they touch the database. Review the SQL. Commit or cancel. The grid keeps investigation fast and makes the write visible before it runs.
-- 3 staged changes, waiting for `a` to apply
BEGIN;
UPDATE orders SET status = 'shipped' WHERE id = 42;
DELETE FROM orders WHERE id = 17;
INSERT INTO orders (customer_id, total) VALUES (88, 149.99);
COMMIT;Click any cell. Delete a row. Insert one. Watch the SQL update live.
| id | name | status | total | |
|---|---|---|---|---|
| 42 | Alice Chen | pending | 149.99 | |
| 43 | Bob Park | shipped | 89.50 | |
| 44 | Carol Diaz | pending | 234.00 | |
| 45 | Dan Kim | returned | 67.25 | |
| 46 | Eve Lu | shipped | 412.80 |
Stage one change or fifty, then inspect the generated SQL. Dadbod Grip sends one BEGIN/COMMIT batch and keeps the staging state when the client reports an error, so you can inspect the database before retrying.
Editing docs →Use DuckDB as a hub for PostgreSQL, MySQL, SQLite, MotherDuck, local files, S3 objects, and HTTPS sources. SQL and attachment credentials travel through standard input instead of process arguments.
Federation docs →A, or gA in the query pad,
sends the request, current SQL, and cached schema metadata to the configured provider.
The request travels through curl config on standard input. Generated SQL
returns for review and does not run automatically. Grid gA stages generated rows instead.
Editing
:GripRename form executes immediately.gA or :GripFill sends the active schema to the configured provider and stages its returned rows for review.gz zooms a pane and restores its split layout; :GripToggle closes Grip buffers.Navigation
gf follows an outgoing foreign key, gm follows incoming references, and <C-o> returns.h/l to fold groups and / to find hidden objects.? shows the current pane’s keys. Digits are contextual: 2 opens SQL from results and history from SQL.j/k, then press Enter.gG opens the ER map. Result shortcut hints fit two rows and stay visible during horizontal scrolling.Analysis
gR profiles distributions, completeness, and cardinality across the table.gQ turns an EXPLAIN plan into cost bars and heuristic index suggestions.gD compares two tables by primary key.s changes the primary sort, while S adds another sort tier.gF builds filters for equality, ranges, patterns, sets, and null values.gP saves the active filters, and gp restores a preset.gx opens an HTTP, HTTPS, or FTP URL from the current cell.Integration
picker option delegates supported lists to Telescope or snacks.nvim.gn loads a notebook copy, and <C-CR> runs its SQL fence or the current SQL paragraph.I/O
gE and gX export the current page or every filtered and sorted row.:GripOpen reads Parquet, CSV, JSON, Excel, ORC, Arrow, IPC, HTTPS, and S3 sources through DuckDB.gW reruns a file query on a timer while no edits are staged.g! enables write mode for supported local files.Attach supported databases to a DuckDB session, then JOIN their prefixed tables with a file read by DuckDB. Private remote files need credentials available to the client.
-- attach your sources
:GripAttach postgres:dbname=production host=db.internal user=app prod
:GripAttach sqlite:archive.db legacy
-- read the Parquet source in the JOIN below
-- then JOIN in the query pad (<C-CR> to run)
SELECT
prod.customers.email,
legacy.orders.total,
enrichment.segment
FROM prod.customers
JOIN legacy.orders ON legacy.orders.customer_id = prod.customers.id
JOIN read_parquet('s3://my-bucket/enrichment.parquet') AS enrichment ON enrichment.email = prod.customers.email-- lazy.nvim
{ "joryeugene/dadbod-grip.nvim" }
-- then connect
:GripConnect