A language server for the SQL files in Rust projects that use sqlx.
The server figures out which database your project targets by asking Cargo
which features are actually resolved for the sqlx dependency (so workspace
and transitive feature unification are handled correctly), builds a schema
index from your migrations, and serves editor features against that schema.
Everything works in .sql files and inside sqlx's query macros in Rust
files: tree-sitter finds the SQL strings of query!, query_as!,
query_scalar! (and their _unchecked variants), and results map back to
Rust buffer coordinates, layering cleanly on top of rust-analyzer.
query_file! is served through the referenced .sql file instead.
- Completion — context-aware: tables after
FROM/JOIN/INTO/UPDATE, a relation's columns afteralias.or in anINSERTcolumn list, and in-scope columns, tables, keywords, and functions elsewhere. Works on incomplete statements; accepting an item replaces the word being typed. - Hover —
CREATE-shaped summaries for tables and views, signatures for columns (naming the defining migration), and curated documentation for keywords and built-in functions. - Goto definition — from any table, alias, or column reference to the defining statement in its migration.
- Find references & document highlight — every use of a table or column
across the whole workspace: open buffers, migration files, standalone
.sqlfiles, and the query macros of closed Rust sources. Aliases and qualifiers count; CTEs stay scoped to their defining statement. - Rename — tables and columns, rewriting queries and migrations across the workspace, closed files included. Validates the new name (reserved words, collisions), refuses objects that exist only in the live database, and sends versioned edits to clients that support them.
- Diagnostics — syntax errors, unknown tables and columns, and
bind-parameter counts checked against a macro's arguments. Served by push
and by pull (
textDocument/diagnostic). - Quick fixes — closest-name suggestions for misspelled tables and columns, ranked by edit distance.
- Semantic tokens — a lexical base layer plus an AST overlay that classifies tables, columns, aliases, and function names; full, delta, and range requests.
- Symbols — document outline of
CREATEstatements with their columns, and workspace-wide search over every known table and column.
Under the hood:
- Database detection —
cargo metadatareports the resolved features of thesqlxdependency;sqlite,postgres, andmysqlselect the SQL dialect, preferringpostgres>mysql>sqlitewhen several are enabled. Details under How detection works. - Per-crate contexts — everything resolves relative to the invoking
crate, exactly like the sqlx macros: its
sqlx.toml, its URL variable (process environment or ancestor.envfiles), its migrations (includingsqlx::migrate!()targets), its backend. A workspace mixing postgres and sqlite crates serves each crate against the right schema and dialect; multi-root workspaces and folder changes mid-session are supported;SQLX_OFFLINE=truedisables live introspection per context. - Schema index — replays a crate's migrations in sqlx version order
and, when
DATABASE_URLpoints at a reachable database, fills in the relations migrations don't cover by read-only introspection — SQLite, PostgreSQL, and MySQL are all supported, and passwords never appear in logs. The index reloads automatically when migrations,Cargo.toml,sqlx.toml, or.envchange (client file watching, with a save-based fallback). - Protocol — incremental document synchronization, UTF-8 position encoding when the client prefers it, and work-done progress while the index loads.
Prebuilt binaries for Linux (gnu/musl), macOS, and Windows are attached to
the GitHub releases — the
rolling nightly prerelease tracks main. Or build from source:
cargo install --git https://github.com/willothy/sqlx-lspThe server speaks LSP over stdio. Point your editor's LSP client at the
sqlx-lsp binary for SQL files — and for Rust files too if you want
features inside the query macros; the server runs happily alongside
rust-analyzer and only answers for the embedded SQL.
Neovim (0.11+):
vim.lsp.config("sqlx_lsp", {
cmd = { "sqlx-lsp" },
filetypes = { "sql", "rust" },
root_markers = { "Cargo.toml" },
})
vim.lsp.enable("sqlx_lsp")VS Code: install sqlx-lsp.vsix from the
releases page with
code --install-extension sqlx-lsp.vsix. The extension lives in
editors/vscode and adds a TextMate injection grammar for
SQL coloring inside the query macros (VS Code takes semantic tokens from
only one provider per document, and rust-analyzer claims Rust files). Set
sqlx-lsp.serverPath if the binary is not on PATH.
Logging goes to stderr; set SQLX_LSP_LOG (a tracing filter, e.g. debug)
to adjust verbosity. Schema loading progress is also reported through
window/logMessage.
cargo metadata resolves the full dependency graph (scanning downward for
the manifest when the editor root is a plain monorepo root). Per crate, the
backend is chosen the way the sqlx macros select a driver: the crate's
database URL scheme decides, gated on the driver features its declared sqlx
dependency (or the workspace-unified feature set) enables; without a URL,
the highest-priority enabled driver wins (postgres > mysql > sqlite). If
detection fails entirely (not a Rust workspace, no sqlx dependency), the
server logs a warning and defaults to SQLite.
cargo test # tests
cargo clippy --all-targetsThe crate is a thin binary over a library (src/lib.rs); the interesting
modules are db (backend detection), workspace (per-crate contexts),
schema/ (migration replay and the schema index), introspect (read-only
introspection for all three backends), analysis/* (the language-feature
implementations), embedded (tree-sitter extraction of SQL from Rust query
macros), and server (the LSP surface).