Browse documentation

Connections

dadbod-grip stores connections in two files that merge automatically. Project connections live in .grip/connections.json at the project root. 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 from the picker, it writes to the project’s .grip/connections.json. Dadbod Grip walks upward from the current working directory to the nearest .git or .grip directory, falling back to the current directory when neither exists. 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
  filters.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 new entries to the global file when it first loads the connection list. 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 opening the connection picker or otherwise loading the list.

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