SQL execution, dataset browser, and schema introspection for Neovim. Part of the Poste family.
Requires: poste.nvim (shared infra + Rust binary)
- Execute SQL statements from
.sqlfiles (PostgreSQL, MySQL, SQLite) - Dataset panel — Paginated results, cell navigation (hjkl), vim-style search/filter, sorting
- Inline editing — Edit cells, insert/delete rows, generate DML with transaction commit
- DB Browser — Tree-view of schemas, tables, columns; generate SELECT/DESCRIBE queries
- SQL completion — Keywords, tables, columns, functions (blink.cmp)
- Schema introspection — PKs, FKs, indexes, DDL
- Export/import — CSV, JSON, SQL INSERT statements
- Multi-result tabs — Each statement gets its own tab
- Execution log viewer — Query history with timing
-- lazy.nvim
{
"beyondlex/poste-sql.nvim",
dependencies= {
"beyondlex/poste.nvim",
"saghen/blink.cmp",
},
config=function()
require("poste-sql.init").setup()
end,
}Open a .sql file and press <CR> on a statement to execute.
Connections are defined in connections.toml (walked up from the SQL file):
[pg-dev]
dialect = "postgres"host = "localhost"port = 5432database = "myapp"user = "{{PG_DEV_USER}}"password = "{{PG_DEV_PASSWORD}}"Sensitive fields support {{VAR}} references resolved at runtime from a
.env file next to connections.toml (same walk-up discovery), with real OS
environment variables taking precedence. Unknown references stay literal, so
plaintext configs keep working. Copy .env.example to .env and keep .env
out of version control — never commit credentials. user and password are
percent-encoded automatically when building connection URLs, so values
containing @, :, /, % etc. work as-is.
Reference in .sql files:
-- @connection pg-devSELECT*FROM users WHERE active = true;The USE database; statement switches the active database for parsing/completion context.
The current connection and database are shown in the statusline as [connection/database] when mini.statusline is installed. The context updates as you move the cursor (respects @connection, @database, and USE statements).
Per-connection colors — add a color or link field in connections.toml:
[production]
color = "#ff0000"
[staging]
link = "WarningMsg"
[development]
color = "SkyBlue"| Field | Type | Example |
|---|---|---|
color = "#rrggbb" | Hex color | color = "#ff0000" |
color = "CSS" | CSS named color | color = "Red", color = "SkyBlue" |
color = "HL" | Highlight group (auto-detected) | color = "Function" |
link = "HL" | Explicit highlight group link | link = "ErrorMsg" |
Auto-detection: color values that are valid Neovim highlight groups are linked (:link), others are treated as CSS color names.
| Key | Action |
|---|---|
h/j/k/l | Move cell |
H/L | Previous/next page |
0/$ | First/last column |
gg/G | First/last row |
s | Sort by column |
<leader>/ | Search |
<leader>ce | Filter by cell |
K | Preview cell |
yy / yc | Yank cell / column |
R | Re-run query |
<Tab>/<S-Tab> | Next/previous tab |
| Key | Action |
|---|---|
i / a | Enter edit mode |
dd | Delete row |
o / O | Insert row below/above |
u | Undo edit |
<leader>w | Commit changes (generate DML) |
| Key | Action |
|---|---|
<leader>ec | Export as CSV |
<leader>ej | Export as JSON |
<leader>es | Export as SQL INSERT |
Press <leader>db in a SQL file to open the database tree browser.
| Key | Action |
|---|---|
<CR> | Toggle node expand/collapse |
x | Context menu |
s | Generate SELECT * |
d | Generate DESCRIBE |
/ | Search filter |
q | Close |
Context menu (x) shows node-specific actions. On schema/database nodes, T inserts a CREATE TABLE template with tab-stop placeholders:
create table table_name (
column_name INTEGER NOT NULL
);
Press <Tab> to jump between placeholders, <S-Tab> to go back.
- Keywords —
SELECT,FROM,WHERE,JOIN, etc. - Tables, columns, schemas — Introspected from your database
- Functions — Aggregate and scalar functions per dialect
- Connection-aware — Completions reflect the actual schema
Requires blink.cmp. Auto-registers as poste_sql source.
Built-in snippets appear as completion items when the prefix matches a trigger word:
| Trigger | Template |
|---|---|
ct | create table |
sf / sl | select * from ... limit 100 |
cnt | select count(*) |
ins | insert into ... values |
upd | update ... set ... where |
del | delete from ... where |
wh | where clause |
cola | alter table add column |
colu | alter table modify column |
cte | with ... as |
idx | create index |
uni | union all |
All snippets use LSP-style syntax (${1:placeholder}, $0 for exit, $$ for literal $). See :help vim.snippet or the LSP spec for details.
Custom snippets via setup():
require("poste-sql").setup({
snippets= {
-- Simple: trigger word → snippet bodymyq="SELECT * FROM ${1:table} WHERE ${2:condition};",
-- Full form: trigger, label, and snippetmyf= {
label="my custom query",
snippet="with ${1:cte} as (\n ${2:select_query}\n)\nselect * from ${1:cte};",
},
},
})# Start test databases (PG 16 on 15432, MySQL 8.0 on 13306)cd tests/sql && docker compose up -d
# Run queries
cargo run --manifest-path ../poste.nvim/Cargo.toml -- run tests/sql/queries/postgres.sql --line 4 --env dev
# Run Lua tests
tests/run.shMIT