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:
| Field | Purpose |
|---|---|
id | Opaque saved-query binding that Dadbod Grip assigns lazily and preserves through edits. |
type | Explicit adapter or file type when the URL does not provide enough information. |
env_file | A .env file that supplies ${VAR} values used by the URL. |
mode | "ro" requests the database client’s read-only mode. |
color | A named or hexadecimal accent color for the connection. |
attachments | DuckDB 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:
| Indicator | Meaning |
|---|---|
* | Last query succeeded |
x | Last 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://...' },
}