
How to Install and Configure Neovim (2025 Guide)
A clean and painless guide to turning Neovim into a modern IDE.
Neovim is a Vim-based text editor built for extensibility and usability. In this tutorial, you’ll learn how to set it up with plugins, keybinds, and full LSP support. This guide assumes you’re using a Unix-like system and are comfortable with basic terminal commands.
1. Install Neovim and dependencies
Use your system’s package manager to install Neovim, along with a few tools that will be required later (like
npm
andripgrep
).
# Gentoo example
sudo emerge app-editors/neovim
sudo emerge net-libs/nodejs
sudo emerge sys-apps/ripgrep
# Arch example
sudo pacman -S neovim nodejs npm ripgrep
2. Set up your Neovim config directory
We’ll create the config folder and add our main config file,
init.lua
.
mkdir -p ~/.config/nvim
cd ~/.config/nvim
nvim .
Inside Neovim, press
%
to create a new file namedinit.lua
. Then add a test print:
print("I use Neovim by the way")
Save and quit with
:wq
, then reopen Neovim. You should see the printed message.
3. Create a Lua module for options
Neovim’s Lua-based config allows us to split logic. Let’s make an
options.lua
file to set basic editor preferences.
mkdir -p ~/.config/nvim/lua/config
nvim lua/config/options.lua
Add some basic options:
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.cursorline = true
vim.opt.shiftwidth = 4
Now, require it in
init.lua
:
require("config.options")
4. Add keybindings
We’ll set our leader key and create a shortcut to open netrw quickly.
nvim lua/config/keybinds.lua
vim.g.mapleader = " "
vim.keymap.set("n", "<leader>cd", vim.cmd.Ex)
And include it in your
init.lua
:
require("config.keybinds")
5. Install Lazy.nvim (plugin manager)
Lazy is a modern plugin manager. Clone it into your runtime path:
-- lua/config/lazy.lua
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable",
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup({})
Include Lazy in
init.lua
:
require("config.lazy")
6. Add a theme plugin
Add a plugin for theming and set it up with Lazy.
-- lua/plugins/colors.lua
return {
"folke/tokyonight.nvim",
config = function()
vim.cmd.colorscheme("tokyonight")
end,
}
7. Add Telescope for fuzzy finding
Telescope allows you to search files, text, and buffers.
-- lua/plugins/telescope.lua
return {
"nvim-telescope/telescope.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
config = function()
local builtin = require("telescope.builtin")
vim.keymap.set("n", "<leader>ff", builtin.find_files)
vim.keymap.set("n", "<leader>fg", builtin.live_grep)
vim.keymap.set("n", "<leader>fb", builtin.buffers)
vim.keymap.set("n", "<leader>fh", builtin.help_tags)
end,
}
8. Add Treesitter for syntax highlighting
Treesitter provides fast and accurate syntax parsing.
-- lua/plugins/treesitter.lua
return {
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
config = function()
require("nvim-treesitter.configs").setup({
highlight = { enable = true },
indent = { enable = true },
ensure_installed = { "lua" },
auto_install = false,
})
end,
}
9. Add Harpoon for file bookmarking
Harpoon lets you quickly switch between frequently edited files.
-- lua/plugins/harpoon.lua
return {
"ThePrimeagen/harpoon",
config = function()
local harpoon = require("harpoon")
vim.keymap.set("n", "<leader>a", function() harpoon:list():add() end)
vim.keymap.set("n", "<C-e>", function() harpoon.ui:toggle_quick_menu(harpoon:list()) end)
end,
}
10. Add LSP, autocompletion, and snippets
For full IDE features, you’ll need LSP config, autocompletion, and snippets.
-- lua/plugins/lsp.lua
return {
"neovim/nvim-lspconfig",
dependencies = {
"williamboman/mason.nvim",
"hrsh7th/nvim-cmp",
"L3MON4D3/LuaSnip",
},
config = function()
require("mason").setup()
require("mason-lspconfig").setup({ ensure_installed = { "lua_ls" } })
local lspconfig = require("lspconfig")
lspconfig.lua_ls.setup({})
local cmp = require("cmp")
cmp.setup({
snippet = {
expand = function(args)
require("luasnip").lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset.insert({
["<Tab>"] = cmp.mapping.select_next_item(),
["<S-Tab>"] = cmp.mapping.select_prev_item(),
}),
sources = { { name = "nvim_lsp" }, { name = "luasnip" } },
})
end,
}
11. One-liner utility plugins
Throw small config-free utilities into one file to avoid bloat.
-- lua/plugins/oneliners.lua
return {
{ "tpope/vim-fugitive" },
{ "ojroques/nvim-osc52" },
{ "norcalli/nvim-colorizer.lua", config = function()
require("colorizer").setup()
end,
},
}
Final init.lua
Example
require("config.options")
require("config.keybinds")
require("config.lazy")
Lazy will automatically load any plugin files inside
lua/plugins
.
You’re now ready to use Neovim as a modern, fast, and extensible code editor. Questions? Drop them in the comments.