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 clone away from feeling like home.
  • Modal editing pays off. You spend a week slower. After that, every edit is a short sentence: ciw changes the word under the cursor, dap deletes 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:

ToolWhyCheck
Neovim ≥ 0.11.2LazyVim’s minimum, built with LuaJITnvim --version
git ≥ 2.19lazy.nvim clones plugins with partial clonesgit --version
A Nerd FontThe icons in the file tree, status line and dashboardGhostty ships one
A C compiler + tree-sitter-clinvim-treesitter compiles its parsers locallycc --version, tree-sitter --version
ripgrep, fd, fzfGrep, find files, and the fuzzy pickerrg --version
lazygitThe git UI behind Space g glazygit --version
curlThe completion engine downloads its binaryalready 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:

bash
xcode-select --install
curl -fsSL https://install.kristoffer.dev/dotfiles | bash -s -- --tools

Then the four tools LazyVim searches with:

bash
brew install ripgrep fd fzf tree-sitter-cli

That is all. Open Ghostty, type nvim, and skip ahead to first launch.

macOS: by hand

No dotfiles, just Neovim and what LazyVim needs:

bash
xcode-select --install
brew install neovim git ripgrep fd fzf lazygit tree-sitter-cli
brew install --cask ghostty

Ghostty ships with a Nerd Font. In iTerm2, WezTerm or kitty, install one and select it in the terminal’s settings:

bash
brew install --cask font-jetbrains-mono-nerd-font

Ubuntu, Debian and WSL

Homebrew for Linux is the easy way: current versions of everything, the same commands as on a Mac.

bash
sudo apt install -y build-essential curl git
brew install neovim ripgrep fd fzf lazygit tree-sitter-cli

If you would rather not use Homebrew, the official release tarball is always current:

bash
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"' >> ~/.zshrc

Windows

My honest advice is WSL, then the Ubuntu steps above. Neovim does run natively:

powershell
winget install Neovim.Neovim
scoop install git ripgrep fd fzf lazygit tree-sitter mingw

Verify the installation

First the version. Anything from 0.11.2 up is fine:

bash
nvim --version | head -1

Then 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:

vim
:checkhealth

A 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:

bash
ls -l ~/.config/nvim   # → ~/dotfiles/.config/nvim

Just my Neovim config

Only the editor, none of the shell:

bash
git clone https://github.com/KristofferRisa/dotfiles ~/dotfiles
ln -s ~/dotfiles/.config/nvim ~/.config/nvim

The LazyVim starter

A clean LazyVim to make your own. Back up any old config first:

bash
mv ~/.config/nvim{,.bak}
mv ~/.local/share/nvim{,.bak}
git clone https://github.com/LazyVim/starter ~/.config/nvim
rm -rf ~/.config/nvim/.git

First launch

bash
nvim

The 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:

  • :Lazy shows the plugins, and updates them with U
  • :LazyExtras turns bundles of plugins on and off with x: a language, a debugger, an AI tool
  • :Mason shows 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:

~/.config/nvim/lazyvim.json
{
  "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:

KeyDoes
F5Start / continue
F10Step over
F11Step into
F12Step out
SpacedbToggle a breakpoint
SpaceduToggle 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.

KeyDoes
SpaceacToggle Claude
SpaceabAdd the current buffer
SpaceasSend the selection (visual mode)
SpaceaaAccept the diff
SpaceadDeny 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

KeyDoes
SpaceSpaceFind a file
Space/Grep the project
SpaceeFile explorer
Space,Switch buffer
SpaceskSearch the keymaps
Spacegglazygit
Ctrl+/A terminal

Read and change code

KeyDoes
gdGo to definition
grReferences
KHover docs
SpacecaCode action
SpacecrRename
SpacecfFormat
gccComment the line

Windows, buffers, quitting

KeyDoes
Space-Split below
Space|Split right
Ctrl+hCtrl+lMove between splits
[b ]bPrevious / next buffer
SpacebdClose the buffer
Ctrl+sSave
SpaceqqQuit 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 (k goes back up)
  • Ctrl-d Half a page down (C-u goes up)
  • } Jump to the next heading
  • gg Back to the top
  • G All the way to the bottom
  • / Search this page; n finds the next match
  • Spacee Open the explorer, the way Space e does 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) or sudo 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 --version says 0.11.2 or newer
  • First nvim launch, and let the plugins install
  • :checkhealth shows 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 d and Space 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:

bash
rm -rf ~/.local/share/nvim ~/.local/state/nvim ~/.cache/nvim

What’s next?