Minimalistic Modern LSP Setup in Neovim with lazy.nvim
March 20, 2025 (about 1 month ago)
-
If you're customizing Neovim and want a more powerful coding experience - real-time diagnostics, go-to-definition, smart completion, code actions - you'll want LSP.
This post walks you through a minimal LSP setup using lazy.nvim for plugin management.
What is LSP?
LSP stands for Language Server Protocol — it defines a standard way for editors and language-specific servers to communicate.
By connecting Neovim to language servers, you get:
- Syntax checking (errors, warnings)
- Auto-completion
- Go-to-definition, references
- Hover documentation
- Code actions (like quick-fixes, rename, refactor)
- Formatting
Plugins Used
We’ll use the following Neovim plugins:
-
mason.nvim
Easily install and manage LSP servers, formatters, linters, and debuggers from inside Neovim. -
mason-lspconfig.nvim
A bridge between Mason and Neovim’s built-in LSP client. It ensures the correct servers are installed and makes them easy to configure. -
nvim-lspconfig
Official plugin for configuring and launching language servers. It handles the actual connection between Neovim and each server.
Step 1: Create lsp-config.lua
To keep things organized, start by creating a new file for LSP-related plugins:
~/.config/nvim/lua/plugins/lsp-config.lua
If you're using a plugin manager like lazy.nvim
or packer.nvim
, this is where you’ll define and configure your LSP setup.
Step 2: Install mason.nvim
— A Package Manager for LSPs
First, we need a way to install and manage language servers without dealing with npm, pip, or system package managers. That’s exactly what
mason.nvim
does.
What is Mason?
mason.nvim
is a plugin that downloads and manages:
- LSP servers
- Formatters (like
prettier
,black
,clang-format
) - Linters (like
eslint
,flake8
) - Debuggers
All directly from Neovim — cross-platform and without leaving your config.
Add this to your lsp-config.lua
:
{
'williamboman/mason.nvim',
opts = {},
}
Now What?
Restart Neovim and run:
:Mason
This opens an UI where you can:
- Browse all available LSP servers, linters, and formatters
- Install or uninstall them with a keypress
- See what's already installed
At this point, Mason can manage tools — but Neovim doesn’t yet know which language servers you want or how to talk to them. Let’s fix that next.
Step 3: Install mason-lspconfig.nvim
— Connecting Mason to Neovim
Now that mason.nvim
is installed, you might be wondering:
“How does Neovim know which LSP servers to actually set up and connect to my code?”
That’s where mason-lspconfig.nvim
comes in.
Why We Use mason-lspconfig.nvim
This plugin acts as a bridge between Mason and Neovim's built-in LSP client. It:
- Automatically installs LSP servers listed in
ensure_installed
- Helps match Mason’s internal server names to the config names expected by Neovim
- Makes setup smoother and less error-prone
Add this to your lsp-config.lua
:
{
"williamboman/mason-lspconfig.nvim",
config = function()
require("mason-lspconfig").setup({
ensure_installed = {
"lua_ls",
"pyright",
"tsserver",
"rust_analyzer",
"clangd"
}
})
end
}
This tells Mason to automatically install these popular LSP servers on startup:
lua_ls
: for Lua (great for configuring Neovim)pyright
: Pythontsserver
: JavaScript & TypeScriptrust_analyzer
: Rustclangd
: C and C++
You can find the full list of supported servers here.
After this step:
Neovim now knows:
- Which LSP servers to install
- Where to find them (via Mason)
- That these servers are available for connection
But we still haven’t actually hooked up Neovim to the servers. That’s what we’ll handle next using nvim-lspconfig
.
Step 4: Connect to LSP Servers with nvim-lspconfig
So far, we've told Mason which language servers to install and manage. But installing the servers is only half of the setup — we still need to tell Neovim how to connect to each server and actually start using them.
That's exactly what nvim-lspconfig
is for.
What is nvim-lspconfig
?
nvim-lspconfig
is the official plugin maintained by the Neovim team that provides easy configurations for connecting to LSP servers. Each language server needs to be started with
some settings, and this plugin handles the boilerplate for you.
In short, it’s the final link in the chain:
- Mason installs the servers
mason-lspconfig
tells us which ones we wantnvim-lspconfig
starts them and connects them to Neovim
Without this, the servers would be installed on your system, but Neovim wouldn’t use them.
Add this to your lsp-config.lua
:
{
"neovim/nvim-lspconfig",
config = function()
local lspconfig = require("lspconfig")
lspconfig.lua_ls.setup({})
lspconfig.rust_analyzer.setup({})
lspconfig.clangd.setup({})
lspconfig.eslint.setup({})
lspconfig.rome.setup({})
lspconfig.pyre.setup({})
end
}
This code:
- Loads the
lspconfig
module - Calls
.setup({})
for each installed server - Initializes each language server so it attaches to your files when you open them
You can customize the {}
part for each server to pass in specific settings, root directories, or formatting options — but keeping it empty works as a good starting point.
How to Check if It's Working
Once you've saved your config and restarted Neovim, open a file in one of the supported languages (like .lua
, .py
, or .rs
), and run:
:LspInfo
This will show you:
- Which servers are currently installed
- Which ones are attached to your current buffer
- Whether your LSP setup is working properly
You should also see things like:
- Function names and types on hover
- Inline diagnostics under problematic code
- Completion suggestions from the language server
At this point, you're connected — LSP is up and running.
(Optional) Telescope UI for Code Actions
Create telescope.lua
under lua/plugins/
:
return {
{
'nvim-telescope/telescope.nvim', tag = '0.1.8',
dependencies = { 'nvim-lua/plenary.nvim' },
config = function()
local builtin = require("telescope.builtin")
vim.keymap.set('n', '<C-p>', builtin.find_files, {})
vim.keymap.set('n', '<leader>fg', builtin.live_grep, {})
end
},
{
'nvim-telescope/telescope-ui-select.nvim',
config = function()
require("telescope").setup {
extensions = {
["ui-select"] = {
require("telescope.themes").get_dropdown {}
}
}
}
require("telescope").load_extension("ui-select")
end
}
}
Explanation:
telescope-ui-select
replaces boring vim selection prompts with Telescope dropdowns.- Now when you press
<space>ca
, you'll get a clean dropdown for code actions.
Result
With this setup:
- LSP servers are installed automatically.
- Neovim is connected to the servers and offers full IDE functionality.
- Keymaps work out-of-the-box when a server is active.
- Code actions look great thanks to Telescope.
It’s minimal, modular, and fully powered by lazy.nvim.