Browse documentation

Connections

dadbod-grip stores connections in two files that merge automatically. Project connections live in .grip/connections.json relative to the current working directory. Global connections live in ~/.grip/connections.json and appear in every project. You never need to configure the merge: opening the connection picker shows both.

Project connections

When you save a connection via :GripConnect, it writes to .grip/connections.json in the current working directory. These connections are scoped to that project. If you open a different project, project connections from the first directory do not appear.

.grip/
  connections.json    project-specific connections
  queries/            saved queries
  filter_presets.json saved filter presets

Check .grip/connections.json into version control only when every URL is credential-free or uses a ${VAR} placeholder. Keep literal passwords out of both project and global files.

Connection entries accept these optional fields in addition to name and url:

FieldPurpose
idOpaque saved-query binding that Dadbod Grip assigns lazily and preserves through edits.
typeExplicit adapter or file type when the URL does not provide enough information.
env_fileA .env file that supplies ${VAR} values used by the URL.
mode"ro" requests the database client’s read-only mode.
colorA named or hexadecimal accent color for the connection.
attachmentsDuckDB federation attachments that restore on reconnect.

Existing connection files remain readable without these fields.

Global connections

~/.grip/connections.json stores connections that appear in every project, regardless of working directory. When at least one global connection exists, the picker groups all connections under labelled sections:

global
  prod-postgres      * postgresql://...
  analytics-duckdb   * duckdb:path/to/analytics.duckdb

project
  local-sqlite       * sqlite:./data.db

Add connections to the global file by promoting them from the picker (see below), or edit the file directly.

Promoting a connection

Press G on any project connection in the picker to copy it to ~/.grip/connections.json. The project entry remains in place. In other projects, the copied entry appears in the global section; in the original project, URL deduplication continues to prefer the project entry.

This is the fastest way to build up your global connection list: connect to a database once per project, then promote the connections you use most.

Health indicators

Each connection shows a health indicator next to its name:

IndicatorMeaning
*Last query succeeded
xLast query failed
(blank)Not yet tested this session

Press T on any connection in the picker to run a test query and update the indicator immediately. File-based connections (CSV, Parquet, SQLite) retest by checking that the file exists and is readable.

File-based connections

Parquet, CSV, TSV, JSON, NDJSON, JSONL, XLSX, ORC, Arrow, and IPC files appear automatically in a “Local Files” section when matching files exist in the current working directory. You do not need to add them manually.

Press s on any local file entry to save it as a named connection. The name defaults to the filename. Saved file connections persist across sessions and appear alongside database connections.

local files
  sales_2025.csv         (cwd)
  analytics.parquet      (cwd)

Remote files accessible via DuckDB httpfs (https://host/data.parquet) must be added manually as named connections.

Shared team config

Set connections_path to point the entire team at one shared file:

require('dadbod-grip').setup({
  connections_path = '/path/to/team/connections.json',
})

When connections_path is set, grip reads and writes to that file only. The project and global file merge is disabled. Use this for a centralized connections file checked into a shared dotfiles or infrastructure repository.

Keep credentials out of connection files

Use a ${VAR} placeholder in the URL and optionally point the entry at an env_file:

{
  "name": "dev",
  "url": "postgresql://api:${DEV_DB_PASSWORD}@dev.internal:5432/app",
  "env_file": "~/work/api/.env"
}

Dadbod Grip resolves the placeholder only while dispatching a database command. The expanded URL is not written back to a connection or saved-query file. An unset or empty variable stops the connection instead of falling through to another credential source.

Environment placeholders keep resolved credentials out of saved files and child-process arguments. They do not hide those values from other processes running as the same operating-system user.

Saved-query connection binding

New query files store an opaque connection ID:

-- grip:connection=conn_0123456789abcdef01234567
SELECT * FROM orders;

The ID resolves across project, global, or custom connection sources. Renaming, promoting, deduplicating, or editing a persisted connection preserves its ID. If the active connection is not persisted, :GripSave saves the SQL without a binding and asks you to save the connection first.

Legacy query files containing -- grip:url= remain readable when the URL is templated or credential-free. Dadbod Grip never auto-connects a credential-bearing legacy URL. It removes that metadata from the editor and warns without displaying the secret. The next explicit save converts a resolvable legacy binding to an ID.

Backward compatibility

If you use g:dbs (vim-dadbod-ui format), dadbod-grip reads those entries automatically and persists them to the global file on first save. Existing vim-dadbod-ui configurations work without changes.

If a g:dbs URL contains a literal password, that migration will persist the literal password. Replace it with a ${VAR} placeholder before the first save.

-- existing vim-dadbod-ui config: works as-is
vim.g.dbs = {
  { name = 'prod', url = 'postgresql://...' },
}