Neovim is Vim with the parts that aged badly replaced: Lua instead of Vimscript, a language server client built in, and syntax trees instead of regular expressions. It is still the editor that opens in a terminal in a tenth of a second and does not need a mouse.
This is how I set it up on a new machine. I rewrote it the week I set up a new Mac, following it step by step. Every command has a Copy button, and the ones marked Run type themselves into this site’s terminal, so you can see what they do first. At the end there is a checklist that remembers where you got to.
Why Neovim?
- It is fast. It starts before your finger is off the key, even with forty plugins.
- It is a real IDE when you want one. Completion, go to definition, rename, format and debugging all come through the same language servers VS Code uses.
- Its config is code. Lua, in a git repo, linked into place. A new machine is one
git cloneaway from feeling like home. - Modal editing pays off. You spend a week slower. After that, every edit is a short sentence:
ciwchanges the word under the cursor,dapdeletes a paragraph.
I do not configure it from scratch. LazyVim is a distribution: a good default config with sensible plugins that I adjust, not one I have to build.
What you need
LazyVim is picky about versions. Here is the list, and how to check each one:
| Tool | Why | Check |
|---|---|---|
| Neovim ≥ 0.11.2 | LazyVim’s minimum, built with LuaJIT | nvim --version |
| git ≥ 2.19 | lazy.nvim clones plugins with partial clones | git --version |
| A Nerd Font | The icons in the file tree, status line and dashboard | Ghostty ships one |
| A C compiler + tree-sitter-cli | nvim-treesitter compiles its parsers locally | cc --version, tree-sitter --version |
| ripgrep, fd, fzf | Grep, find files, and the fuzzy picker | rg --version |
| lazygit | The git UI behind Space g g | lazygit --version |
| curl | The completion engine downloads its binary | already there |
If you only take away one line, take this one: apt’s Neovim is too old. On Linux, get it from Homebrew or the official tarball.
Install
macOS: the one-liner
This is the path I took on the new Mac. My dotfiles install Neovim, lazygit, zsh, tmux and Ghostty with --tools, and link my Neovim config into ~/.config/nvim at the same time:
xcode-select --install
curl -fsSL https://install.kristoffer.dev/dotfiles | bash -s -- --toolsThen the four tools LazyVim searches with:
brew install ripgrep fd fzf tree-sitter-cliThat is all. Open Ghostty, type nvim, and skip ahead to first launch.
macOS: by hand
No dotfiles, just Neovim and what LazyVim needs:
xcode-select --install
brew install neovim git ripgrep fd fzf lazygit tree-sitter-cli
brew install --cask ghosttyGhostty ships with a Nerd Font. In iTerm2, WezTerm or kitty, install one and select it in the terminal’s settings:
brew install --cask font-jetbrains-mono-nerd-fontUbuntu, Debian and WSL
Homebrew for Linux is the easy way: current versions of everything, the same commands as on a Mac.
sudo apt install -y build-essential curl git
brew install neovim ripgrep fd fzf lazygit tree-sitter-cliIf you would rather not use Homebrew, the official release tarball is always current:
curl -LO https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.tar.gz
sudo rm -rf /opt/nvim-linux-x86_64
sudo tar -C /opt -xzf nvim-linux-x86_64.tar.gz
echo 'export PATH="$PATH:/opt/nvim-linux-x86_64/bin"' >> ~/.zshrcWindows
My honest advice is WSL, then the Ubuntu steps above. Neovim does run natively:
winget install Neovim.Neovim
scoop install git ripgrep fd fzf lazygit tree-sitter mingwVerify the installation
First the version. Anything from 0.11.2 up is fine:
nvim --version | head -1Then ask Neovim itself. :checkhealth runs every plugin’s self-test and tells you exactly what is missing. It is the first thing to do whenever something looks wrong:
:checkhealthA warning about a language you never write (Python providers, Perl, Ruby) is harmless. An error under lazy or nvim-treesitter is not. Fix those first.
Get LazyVim
With my dotfiles
If you ran the one-liner, you are done. ~/.config/nvim is a link into ~/dotfiles, so a change to it is a commit:
ls -l ~/.config/nvim # → ~/dotfiles/.config/nvimJust my Neovim config
Only the editor, none of the shell:
git clone https://github.com/KristofferRisa/dotfiles ~/dotfiles
ln -s ~/dotfiles/.config/nvim ~/.config/nvimThe LazyVim starter
A clean LazyVim to make your own. Back up any old config first:
mv ~/.config/nvim{,.bak}
mv ~/.local/share/nvim{,.bak}
git clone https://github.com/LazyVim/starter ~/.config/nvim
rm -rf ~/.config/nvim/.gitFirst launch
nvimThe first start installs every plugin, then Mason installs the language servers. It looks like a wall of scrolling text. Give it a minute, then press q and restart.
After that, three screens are worth knowing:
:Lazyshows the plugins, and updates them withU:LazyExtrasturns bundles of plugins on and off withx: a language, a debugger, an AI tool:Masonshows the language servers, formatters and linters it installed
What I added on top
My extras
LazyVim’s defaults cover most things. These are the extras I turned on in :LazyExtras. They live in one file, so they come with the dotfiles:
{
"extras": [
"lazyvim.plugins.extras.ai.claudecode",
"lazyvim.plugins.extras.coding.yanky",
"lazyvim.plugins.extras.dap.core",
"lazyvim.plugins.extras.formatting.prettier",
"lazyvim.plugins.extras.lang.dotnet",
"lazyvim.plugins.extras.lang.go",
"lazyvim.plugins.extras.lang.json",
"lazyvim.plugins.extras.lang.tailwind",
"lazyvim.plugins.extras.lang.vue",
"lazyvim.plugins.extras.test.core",
"lazyvim.plugins.extras.util.dot"
]
}What they give me: language servers and formatting for .NET, Go, Vue, Tailwind and JSON; a debugger; a test runner; a yank history; syntax for dotfiles; and Claude Code in a split.
Debugging .NET
The dap.core extra gives the debugger. lua/plugins/dap.lua points it at netcoredbg and gives it the keys every IDE uses:
| Key | Does |
|---|---|
| F5 | Start / continue |
| F10 | Step over |
| F11 | Step into |
| F12 | Step out |
| Spacedb | Toggle a breakpoint |
| Spacedu | Toggle the debug UI |
It expects netcoredbg unpacked into ~/.local/bin/netcoredbg/. That is the one piece the installer does not do yet.
Claude Code in the editor
The claudecode extra puts Claude Code in a split that sees what I see: the open buffer, the selection, the diagnostics. Its changes arrive as diffs I accept or reject, not as files that silently changed.
| Key | Does |
|---|---|
| Spaceac | Toggle Claude |
| Spaceab | Add the current buffer |
| Spaceas | Send the selection (visual mode) |
| Spaceaa | Accept the diff |
| Spacead | Deny the diff |
The keys that matter
Space is the leader. You do not have to memorise the map: press Space and wait, and which-key lists everything that can come next. These are the ones worth having in your fingers by the end of the first week.
Find things
| Key | Does |
|---|---|
| SpaceSpace | Find a file |
| Space/ | Grep the project |
| Spacee | File explorer |
| Space, | Switch buffer |
| Spacesk | Search the keymaps |
| Spacegg | lazygit |
| Ctrl+/ | A terminal |
Read and change code
| Key | Does |
|---|---|
| gd | Go to definition |
| gr | References |
| K | Hover docs |
| Spaceca | Code action |
| Spacecr | Rename |
| Spacecf | Format |
| gcc | Comment the line |
Windows, buffers, quitting
| Key | Does |
|---|---|
| Space- | Split below |
| Space| | Split right |
| Ctrl+hCtrl+l | Move between splits |
| [b ]b | Previous / next buffer |
| Spacebd | Close the buffer |
| Ctrl+s | Save |
| Spaceqq | Quit everything |
And the one everyone needs on day one: :q quits, :q! quits without saving, :wq saves and quits.
Practise on this page
This site has a vim mode, shaped like LazyVim on purpose: Space is the leader, which-key answers a pause, and Space e opens an explorer. It is a safe place to build the muscle memory, because nothing here can be deleted.
Turn it on with vim on (type it into the site terminal, or click it), close the terminal, and work down the list. Each item ticks itself off when you press its keys.
- j Scroll down a line (
kgoes back up) - Ctrl-d Half a page down (
C-ugoes up) - } Jump to the next heading
- gg Back to the top
- G All the way to the bottom
- / Search this page;
nfinds the next match - Spacee Open the explorer, the way
Space edoes in LazyVim - SpaceSpace Find a file, which here means a post
- Spacesk Search the keymaps
- :checkhealth The site’s own
:checkhealth - :Lazy And its
:Lazy, for what this page loaded - Spaceuz Zen mode, one more time to leave it
Your progress is saved in this browser, so you can come back to it. ? shows every key vim mode knows, and :q turns it off again.
New machine checklist
The whole post as a list. Tick things as you go. The ticks are saved in this browser, so you can close the tab halfway through a setup.
-
xcode-select --install(macOS) orsudo apt install -y build-essential(Linux) - Install Homebrew
- Run the dotfiles one-liner with
--tools -
brew install ripgrep fd fzf tree-sitter-cli - Open Ghostty, or set a Nerd Font in your terminal
-
nvim --versionsays 0.11.2 or newer - First
nvimlaunch, and let the plugins install -
:checkhealthshows no errors under lazy or nvim-treesitter -
:LazyExtras: turn on the languages you write - Add an SSH key, then
gh auth login - Open a real project and try
Space Space,g dandSpace c a - Do the practice lap
- Run
:Tutor: Neovim’s built-in tutorial, thirty minutes well spent
Troubleshooting
Icons show up as boxes or question marks. The terminal font has no Nerd Font glyphs. Ghostty works out of the box. Anywhere else, install a Nerd Font and select it in the terminal, not in Neovim.
“LazyVim requires Neovim >= 0.11.2”. You have a packaged Neovim that is too old, usually from apt. Install it from Homebrew or the tarball, and check that which nvim points to the new one.
Treesitter errors about a missing compiler or tree-sitter. Install tree-sitter-cli and a C compiler (xcode-select --install, or build-essential), then run :TSUpdate.
Yanking over SSH does not reach my clipboard. The dotfiles send it over OSC 52, which needs a terminal that allows it. Ghostty does, with the dotfiles’ config.
Starting over. Neovim keeps its state in three places. Remove them and the next start is a first launch again. Your config is left alone:
rm -rf ~/.local/share/nvim ~/.local/state/nvim ~/.cache/nvimWhat’s next?
- Dotfiles: the rest of the setup, and what the one-liner does
- LazyVim’s documentation: the full keymap and every extra
- My Neovim config on GitHub
:Tutorinside Neovim. It is still the best thirty minutes you can spend on it.
