Neovim on Linux — Complete IDE Tutorial

Intro
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.
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 and ripgrep).
# Gentoo
sudo emerge app-editors/neovim
sudo emerge net-libs/nodejs
sudo emerge sys-apps/ripgrep
# Arch
sudo pacman -S neovim nodejs npm ripgrep
Set up your Neovim config directory
Create your config folder and add the main config file.
mkdir -p ~/.config/nvim
cd ~/.config/nvim
nvim .
In Neovim, press %
to create a new file named init.lua
:
print("I use Neovim by the way")
Save and quit with :wq
, then reopen Neovim.
Create a Lua module for options
mkdir -p ~/.config/nvim/lua/config
nvim lua/config/options.lua
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.cursorline = true
vim.opt.shiftwidth = 4
Then in init.lua
:
require("config.options")
Add keybindings
vim.g.mapleader = " "
vim.keymap.set("n", "<leader>cd", vim.cmd.Ex)
In init.lua
:
require("config.keybinds")
Install Lazy.nvim
Clone it into your runtime path.
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({})
Then:
require("config.lazy")
Add a theme plugin
return {
"folke/tokyonight.nvim",
config = function()
vim.cmd.colorscheme("tokyonight")
end,
}
Add Telescope for fuzzy finding
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,
}
Add Treesitter for syntax highlighting
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,
}
Add Harpoon for file bookmarking
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,
}
Add LSP, autocompletion, and snippets
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,
}
One-liner utility plugins
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")
/home/tony/.config/nvim
├── init.lua
├── lazy-lock.json
├── lua
│ ├── config
│ │ ├── keybinds.lua
│ │ ├── lazy.lua
│ │ └── options.lua
│ └── plugins
│ ├── colors.lua
│ ├── harpoon.lua
│ ├── init.lua
│ ├── lsp.lua
│ ├── lualine.lua
│ ├── one-liners.lua
│ ├── orgmode.lua
│ ├── telescope.lua
│ └── treesitter.lua
├── plugin
│ └── flterm.lua
└── README.md
5 directories, 16 files
My keybinds
If you want to just copy my nvim config, my keybind documentation is here:
General
Mode | Key | Action |
---|---|---|
n | <leader>cd | Open Ex mode (`:Ex`) |
n | J | Join lines while keeping the cursor in place |
n | <C-d> | Scroll half-page down and center cursor |
n | <C-u> | Scroll half-page up and center cursor |
n | n | Next search result (centered) |
n | N | Prev search result (centered) |
n | Q | Disable Ex mode |
n | <C-k> | Next quickfix entry (centered) |
n | <C-j> | Prev quickfix entry (centered) |
n | <leader>k | Next location list entry (centered) |
n | <leader>j | Prev location list entry (centered) |
i | <C-c> | Exit insert mode |
n | <leader>x | Make current file executable |
n | <leader>u | Toggle Undotree |
n | <leader>rl | Reload config |
n | <leader><leader> | Source current file |
Visual Mode
Mode | Key | Action |
---|---|---|
v | J | Move block down |
v | K | Move block up |
x | <leader>p | Paste without overwriting clipboard |
v | <leader>y | Yank to system clipboard |
Linting & Formatting
Mode | Key | Action |
---|---|---|
n | <leader>cc | Run php-cs-fixer |
n | <F3> | Format (LSP) |
Telescope
Mode | Key | Action |
---|---|---|
n | <leader>ff | Find files |
n | <leader>fg | Git-tracked files |
n | <leader>fo | Recent files |
n | <leader>fq | Quickfix list |
n | <leader>fh | Help tags |
n | <leader>fb | Buffers |
n | <leader>fs | Grep string under cursor |
n | <leader>fc | Grep current filename (no extension) |
n | <leader>fi | Search in ~/.config/nvim |
Harpoon
Mode | Key | Action |
---|---|---|
n | <leader>a | Add to Harpoon |
n | <C-e> | Toggle Harpoon quick menu |
n | <leader>fl | Telescope Harpoon marks |
n | <C-p> | Prev Harpoon mark |
n | <C-n> | Next Harpoon mark |
LSP
Mode | Key | Action |
---|---|---|
n | K | Hover docs |
n | gd | Go to definition |
n | gD | Go to declaration |
n | gi | Go to implementation |
n | go | Go to type definition |
n | gr | List references |
n | gs | Signature help |
n | gl | Show diagnostics float |
n | <F2> | Rename symbol |
n,x | <F3> | Format code |
n | <F4> | Code actions |
Misc
Mode | Key | Action |
---|---|---|
n | <leader>dg | Run DogeGenerate |
n | <leader>s | Replace word on current line |
Final Thoughts
You’re now ready to use Neovim as a modern, fast, and extensible code editor.
Thanks so much for checking out this tutorial. If you got value from it, and you want to find more tutorials like this, check out my youtube channel here: YouTube, or my website here: tony,btw
You can support me here: kofi