https://github.com/gentleeduck/duck-sqllsp
Multi-dialect SQL Language Server in Rust. 300+ lint rules, context-aware completion (50 phases), schema-aware hover, formatter, code lenses, inlay hints. PG-first; MySQL / SQLite / MSSQL supported. tower-lsp + libpg_query.
https://github.com/gentleeduck/duck-sqllsp
completion formatter language-server libpg-query linter lsp mssql mysql neovim postgresql rust sql sqlite tower-lsp vscode
Last synced: about 6 hours ago
JSON representation
Multi-dialect SQL Language Server in Rust. 300+ lint rules, context-aware completion (50 phases), schema-aware hover, formatter, code lenses, inlay hints. PG-first; MySQL / SQLite / MSSQL supported. tower-lsp + libpg_query.
- Host: GitHub
- URL: https://github.com/gentleeduck/duck-sqllsp
- Owner: gentleeduck
- License: mit
- Created: 2026-05-24T11:14:09.000Z (about 2 months ago)
- Default Branch: master
- Last Pushed: 2026-06-15T11:22:41.000Z (30 days ago)
- Last Synced: 2026-06-15T13:14:20.248Z (30 days ago)
- Topics: completion, formatter, language-server, libpg-query, linter, lsp, mssql, mysql, neovim, postgresql, rust, sql, sqlite, tower-lsp, vscode
- Language: Rust
- Homepage:
- Size: 3.07 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
- Roadmap: ROADMAP_ADVANCED.md
Awesome Lists containing this project
README
duck-sqllsp
Persistent multi-dialect SQL Language Server. PostgreSQL is the deepest target; MySQL / MariaDB, SQLite, and SQL Server are first-class for syntax, completion, hover, formatting, and connection-backed introspection. Built on tower-lsp + libpg_query.
MIT -
Changelog -
Contributing -
Crate docs
---
## What you get
- **300+ lint rules** (PG-first, dialect-aware) covering schema correctness, transaction safety, query smells, migration footguns, vendor mismatches (MySQL `ENGINE=`, Oracle `DUAL`/`CONNECT BY`, SQL Server `BEGIN TRANSACTION`, ...).
- **Context-aware completion** across ~50 phases: `CREATE INDEX ... USING` + opclass slot, `CREATE TRIGGER ... EXECUTE FUNCTION`, `CREATE POLICY ... FOR / TO`, `ALTER COLUMN TYPE`, `CALL `, PL/pgSQL local-variable scope, JOIN target resolution, etc.
- **Rich hover cards** for tables (compact `CREATE TABLE` + indexes + triggers + policies + comment + `ALTER TABLE OWNER TO`), columns, functions, keywords, types, NULL three-valued logic notes.
- **Offline mode** built in: walks the workspace for `*.sql` files (`migrations/`, `db/`, `sql/`, `schema/`) and derives a synthetic catalog so completion + hover + diagnostics work without a live DB. Live introspect (PG / MySQL / SQLite) overrides.
- **Code lenses**: `Run` above every statement + `EXPLAIN` for DML; `+ LIMIT 100`, `EXPLAIN ANALYZE` for slow SELECTs. VS Code wires them through to the active connection's CLI in a terminal; other clients see no broken-command popups.
- **Inlay hints**: column-name chip per INSERT VALUES tuple (DataGrip-style), `SELECT *` expansion, `JOIN ... ON ...` predicate suggestion, `-- ~N rows` at end of SELECT, literal-cast `::int` hint in WHERE.
- **Formatter**: external `sql-formatter` v15+ reflow + DataGrip-style `CREATE TABLE` alignment + PL/pgSQL block indenter. Optional `singleLine` post-pass collapses DML statements onto one line while leaving DDL intact.
- **Refactors / code actions**: `= NULL` -> `IS NULL`, `EXISTS (...)` -> `CROSS JOIN LATERAL`, `BEGIN TRANSACTION` -> `BEGIN`, extract subquery to `WITH _tmp AS (...) CTE`, 30+ more.
- **Editor integrations**: VS Code extension with connections + schema tree view, neovim setup that works with stock `vim.lsp` + `nvim-cmp`.
## Install
```sh
cargo install duck-sqllsp
```
Library use:
```sh
cargo add dsl-analysis
```
## Quick start
```lua
-- neovim
vim.lsp.config('duck_sqllsp', {
cmd = { 'duck-sqllsp', 'server' },
filetypes = { 'sql', 'mysql', 'plsql' },
root_markers = { '.duck-sqllsp.toml', '.duck-sqllsp.json', '.git' },
})
vim.lsp.enable('duck_sqllsp')
```
```sh
duck-sqllsp --help
duck-sqllsp version
duck-sqllsp rules
duck-sqllsp lint file.sql
duck-sqllsp format file.sql --stdout
duck-sqllsp introspect file.sql # offline catalog from CREATE TABLE/FUNCTION/TYPE
duck-sqllsp introspect --url postgres://user:pass@host/db
```
Project config example (`.duck-sqllsp.toml`):
```toml
[duck_sqllsp]
active_connection = "local"
dialect = "postgres" # postgres / mysql / sqlite / mssql (aliases accepted)
require_connection = false
[duck_sqllsp.style]
keyword = "upper"
function = "lower"
type = "upper"
identifier = "preserve"
[duck_sqllsp.style.createTable]
alignColumns = true
openParenOnNewLine = true
constraintsAtEnd = true
[duck_sqllsp.style.formatter]
language = "postgresql"
expressionWidth = 9999
singleLine = true # collapse DML to one line; leaves DDL untouched
denseOperators = true
[[duck_sqllsp.connections]]
name = "local"
url = "postgres://user:pass@localhost:5432/mydb"
```
## Workspace
| Crate | Role |
| --- | --- |
| [`dsl-parse`](dsl-parse) | SQL parser - libpg_query primary, sqlparser fallback for MySQL/SQLite/MSSQL |
| [`dsl-catalog`](dsl-catalog) | Schema model - tables (incl. owner), columns, constraints (inline + table-level), indexes, triggers, policies, sequences, types, functions |
| [`dsl-knowledge`](dsl-knowledge) | Static keyword / type / function reference with PG-doc links |
| [`dsl-resolve`](dsl-resolve) | Name resolution, FROM / JOIN / LATERAL scope, CTE columns, alias chains |
| [`dsl-format`](dsl-format) | Formatter - sql-formatter reflow + DataGrip alignment + PL/pgSQL indent + optional one-line DML pass |
| [`dsl-analysis`](dsl-analysis) | Lint rule engine - 300+ diagnostics with narrow ranges |
| [`dsl-completion`](dsl-completion) | Context-aware completion engine, ~50 phases, alias + scope aware |
| [`dsl-hover`](dsl-hover) | Hover cards with cursor-side narrowing, schema-qualified resolution |
| [`dsl-conn`](dsl-conn) | Live PG / MySQL / SQLite catalog introspection (sqlx) |
| [`dsl-server`](dsl-server) | tower-lsp server - all 17 LSP request handlers + startup progress |
| [`dsl-cli`](dsl-cli) | `duck-sqllsp` binary - subcommands + stdio LSP + signal handling |
## Editor integrations
- **VS Code**: install `wildduck.duck-sqllsp-vscode`. Sidebar tree views for connections + schema. Commands: Add Connection, Set Active, Test Connection, Refresh Schema, Restart Server, Show Logs. Run / EXPLAIN / EXPLAIN ANALYZE / + LIMIT 100 code lenses wire through to a `duck-sqllsp` terminal running `psql` / `mysql` / `sqlite3` against the active connection.
- **neovim**: stock `vim.lsp` + `nvim-cmp`. duck-sqllsp emits `$/progress` so statusline plugins surface "loading workspace..." while the .sql scan + DB introspect settle.
## Build
```sh
cargo build --release
cargo test --workspace --release
cargo clippy --workspace --all-features --release -- -D warnings
```
2500+ tests (rules, idioms, completion phases, hover resolver, formatter, parsers).
## Performance targets
| Metric | Target |
| --- | --- |
| Completion p50 | < 5 ms |
| Diagnostics p50 | < 20 ms |
| Hover p50 | < 3 ms |
| Format p50 | < 30 ms |
| Memory idle | < 30 MB |
| Memory @ 4 MiB file | < 150 MB |
| Cold start | < 50 ms |
| Document update | incremental, no re-parse on cached handlers |
## Design
- **libpg_query** primary parser, **sqlparser** fallback so MySQL backticks, MSSQL bracketed idents, SQLite quirks all parse.
- **tower-lsp** protocol layer. Every handler is a thin shim over a pure-function crate; the LSP transport is the only place tokio touches.
- **Per-document parse cache** on `OnceLock` - first heavy handler after `didChange` pays the parse cost, the rest reuse it.
- **Space-preserving strip** keeps 1:1 byte offsets when stripping strings / comments / dollar-quoted bodies, so diagnostic ranges map back to source byte-exact.
- **Catalog snapshots** are `parking_lot::RwLock` reads cloned before any `.await` - no guard ever crosses an await point.
- **`PR_SET_PDEATHSIG`** + SIGTERM / SIGINT / SIGHUP handling - the binary always dies with its editor.
## Sibling repos
[`@gentleduck/ui`](https://github.com/gentleeduck/duck-ui) -
[`@gentleduck/iam`](https://github.com/gentleeduck/duck-iam) -
[`@gentleduck/upload`](https://github.com/gentleeduck/duck-upload) -
[`@gentleduck/md`](https://github.com/gentleeduck/duck-md)
## Contributing
PR checklist + style notes in [`CONTRIBUTING.md`](CONTRIBUTING.md).
Security: [`SECURITY.md`](SECURITY.md). Behaviour: [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md).
## License
MIT. See [`LICENSE`](LICENSE).