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:

ServerWhy capabilities are adjusted
basedpyrightHandles Python definitions and hover, but avoids formatting and rename.
ruffHandles linting and code actions, but hover and definition stay with Pyright.
tyExperimental Python type checking should not claim every feature.
vue_ls and TypeScript serversSemantic token conflicts are reduced.
r_language_serverCompletion 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