Turn Neovim into a Full IDE with LSP, Treesitter, and Telescope
One init.lua takes bare Neovim 0.12 to autocomplete, fuzzy finding, and syntax-aware navigation.
What you'll build
Starting from a bare Neovim install and one init.lua, you'll end up with a language-aware editor: syntax-aware highlighting via Treesitter, fuzzy file/text search via Telescope, and a working language server with go-to-definition, rename, and autocomplete — no distribution, no copied kitchen-sink config.
Prerequisites
Verified against Neovim 0.12.4 (stable), lazy.nvim (stable branch), nvim-treesitter main, telescope.nvim latest release, and mason.nvim 2.3.1.
- Neovim ≥ 0.12 — the nvim-treesitter rewrite requires it. macOS:
brew install neovim. Linux: distro packages lag badly; grab the tarball or AppImage from Neovim's releases page. - git and a C compiler (clang or gcc — on macOS,
xcode-select --install) for cloning plugins and compiling parsers. - ripgrep (
brew install ripgrep/apt install ripgrep) — Telescope'slive_grepwon't work without it. - tree-sitter CLI ≥ 0.26.1 —
brew install tree-sitter,cargo install tree-sitter-cli, or a release binary. The nvim-treesitter README explicitly says not to install it via npm.
Back up any existing config first: mv ~/.config/nvim ~/.config/nvim.bak.
1. Bootstrap the plugin manager
Create ~/.config/nvim/init.lua. Everything in this tutorial goes in this one file, top to bottom. Start with lazy.nvim, which installs itself on first launch:
vim.g.mapleader = " "
vim.g.maplocalleader = "\\"
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable",
"https://github.com/folke/lazy.nvim.git", lazypath })
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup({
spec = {
{ "nvim-treesitter/nvim-treesitter", branch = "main", lazy = false, build = ":TSUpdate" },
{ "nvim-telescope/telescope.nvim", version = "*",
dependencies = { "nvim-lua/plenary.nvim" } },
{ "mason-org/mason.nvim", opts = {} },
{ "neovim/nvim-lspconfig" },
},
})
Leader must be set before lazy.setup so plugin keymaps bind correctly.
2. Syntax-aware highlighting with Treesitter
nvim-treesitter's main branch is a full rewrite: no more configs.setup{}. You install parsers, then start highlighting per filetype. Append:
require("nvim-treesitter").install({ "lua", "python", "javascript" })
vim.api.nvim_create_autocmd("FileType", {
pattern = { "lua", "python", "javascript" },
callback = function() vim.treesitter.start() end,
})
Swap in the languages you actually use; parsers compile in the background on first launch.
3. Fuzzy finding with Telescope
telescope.nvim is already in the spec above — it just needs keymaps. Append:
local builtin = require("telescope.builtin")
vim.keymap.set("n", "<leader>ff", builtin.find_files, { desc = "Find files" })
vim.keymap.set("n", "<leader>fg", builtin.live_grep, { desc = "Live grep" })
vim.keymap.set("n", "<leader>fb", builtin.buffers, { desc = "Buffers" })
vim.keymap.set("n", "<leader>fh", builtin.help_tags, { desc = "Help tags" })
4. Wire up a language server
Since 0.11, LSP config is native: nvim-lspconfig now just ships ready-made configs that you activate with vim.lsp.enable(), and mason.nvim installs the server binaries and puts them on Neovim's PATH. Append:
vim.lsp.enable("lua_ls")
We're using the Lua server because your config is Lua — instant dogfooding. Now launch nvim, let lazy.nvim finish cloning, then install the server and restart:
:MasonInstall lua-language-server
:qa
Neovim 0.11+ ships LSP keymaps by default: grn rename, grr references, gra code action, gri implementation, gO document symbols, K hover, Ctrl-] definition.
5. Turn on autocomplete
No completion plugin needed — the built-in LSP completion autotriggers as you type. Append:
vim.api.nvim_create_autocmd("LspAttach", {
callback = function(ev)
local client = assert(vim.lsp.get_client_by_id(ev.data.client_id))
if client:supports_method("textDocument/completion") then
vim.lsp.completion.enable(true, client.id, ev.buf, { autotrigger = true })
end
end,
})
Accept a completion with Ctrl-y.
Verify it works
Open your own config: nvim ~/.config/nvim/init.lua, then run :checkhealth vim.lsp. You should see lua_ls listed under active clients:
- Active Clients: ~
- lua_ls (id: 1)
Then confirm each piece: :checkhealth nvim-treesitter shows the installed parsers with no errors, keywords in your config are colored by Treesitter, K on vim.keymap pops up docs, typing vim.fn. in insert mode opens a completion menu, and <Space>ff opens the Telescope file picker.
Troubleshooting
-
module 'nvim-treesitter.configs' not found— you pasted a pre-rewrite snippet from an older tutorial. Themainbranch has noconfigsmodule; use theinstall()+vim.treesitter.start()pattern from step 2. -
lua-language-server is not executableon opening a Lua file — the server isn't installed yet or Mason hasn't loaded. Run:MasonInstall lua-language-server, then restart Neovim. -
Undefined global 'vim'diagnostics all over init.lua — lua_ls doesn't know it's inside Neovim. Add abovevim.lsp.enable("lua_ls"):vim.lsp.config("lua_ls", { settings = { Lua = { diagnostics = { globals = { "vim" } } } }, }) -
live_grepshows nothing — ripgrep is missing.:checkhealth telescopewill flagrg: not found; install it and restart.
Next steps
Add servers for your real languages the same way: :MasonInstall pyright, then vim.lsp.enable("pyright") — nvim-lspconfig's README lists every config name. From there: telescope-fzf-native for faster sorting, nvim-treesitter-textobjects for syntax-aware motions, format-on-save via the LspAttach example in :help lsp-attach, and Neovim 0.12's experimental built-in vim.pack if you'd rather drop the plugin manager entirely.
Sources & further reading
- Neovim LSP documentation — neovim.io
- lazy.nvim Installation — lazy.folke.io
- nvim-treesitter (main branch) README — github.com
- telescope.nvim README — github.com
- mason.nvim README — github.com
- nvim-lspconfig README — github.com
Lenn writes about cloud platforms, Kubernetes internals, and the infrastructure decisions that quietly make or break engineering organizations. Based in Berlin's vibrant tech scene, they have a talent for turning dense platform-engineering topics into prose that people actually finish reading.
Discussion 0
No comments yet
Be the first to weigh in.