Neovim LSP Architecture
Up: Neovim Config Tutorial Down: LSP servers, platforms, LSP completion plugins
The LSP layer is a dispatch office. It does not own the language servers. It knows how to talk to them after the project environment puts them on $PATH.
Native Config Priority
Server configs live under root lsp/*.lua, and custom logic in lua/lsp/init.lua uses Neovim’s native LSP configuration model.
The tutorial rule is:
vim.lsp.config("server_name", {
cmd = { "server-binary" },
})On NixOS, server-binary should be available from the system or the active project shell.
NixOS Path Strategy
The TypeScript and Vue setup shows the pattern clearly. On NixOS, the config resolves TypeScript SDK and Vue server paths from installed binaries in the environment. On non-Nix Linux, it can fall back to Mason package directories.
That split keeps the same Neovim Lua working on both platforms.
LSP Attach Behavior
When an LSP attaches, the config installs maps for actions such as code actions, hover, formatting, diagnostics, symbols, definitions, references, and server capabilities.
which-key.nvim labels these maps so the LSP command surface stays discoverable.
Capability Pruning
Some servers are intentionally narrowed:
| Server | Why capabilities are adjusted |
|---|---|
basedpyright | Handles Python definitions and hover, but avoids formatting and rename. |
ruff | Handles linting and code actions, but hover and definition stay with Pyright. |
ty | Experimental Python type checking should not claim every feature. |
vue_ls and TypeScript servers | Semantic token conflicts are reduced. |
r_language_server | Completion and formatting can be handled elsewhere. |
Watchman
If watchman is installed, the config replaces Neovim’s default LSP file watcher with a Watchman-backed watcher. Large projects benefit because file watching becomes less naive.
Related: LSP servers, completion cockpit