Set up Neovim with LazyVim
Turn Neovim into a full editor with LazyVim, with support for Go, TypeScript, Terraform, Docker, Helm and YAML, a transparent Tokyo Night theme, and Claude Code one key away.
- Platform
- macOS on Apple silicon
- Time
- About 20 minutes
- Steps
- 11
Neovim is a fast, keyboard-driven text editor that runs in your terminal.
LazyVim is a ready-made Neovim setup that adds a file explorer, fuzzy search, code completion, language servers and Git tools, and stays easy to change.
This guide installs both and turns on support for Go, TypeScript, Terraform, Docker, Helm, JSON and YAML.
It then adds a few personal touches: a transparent Tokyo Night theme, jj to leave insert mode, a Kubernetes-friendly YAML formatter, and Claude Code in a split.
Run every command in Ghostty.
Verified with Neovim 0.12.5 · LazyVim 16.0.1 · macOS 27.0
steps
Step 1: Install Neovim and its helpersNeovim itself, plus the search, Git and parser tools LazyVim uses.
Install Neovim and the command line tools LazyVim relies on:
Terminal brew install neovim ripgrep fd fzf lazygit tree-sitter-cliWhat each one does:
neovimis the editor. You start it withnvim.ripgrepandfdpower the search across file contents and file names.fzfis a fuzzy finder that LazyVim's health check looks for.lazygitis a full Git screen you can open inside Neovim.tree-sitter-clibuilds the parsers behind accurate syntax highlighting, using the C compiler that came with Homebrew.
Check the version:
Terminal nvim --version | head -1Expected output (yours may be newer) NVIM v0.12.5LazyVim needs Neovim 0.11.2 or newer.
Step 2: Install the language toolsGo, Node.js, yamlfmt and OpenTofu, which the language support calls behind the scenes.
LazyVim installs language servers for you, but it builds some of them with Go or Node.js, and two formatters in this setup run their own programs. Install all four:
Terminal brew install go node yamlfmt opentofugolets LazyVim install gopls, the Go language server, along with the Go formatters and debugger.nodelets it install the TypeScript, JSON, YAML and Docker language servers.yamlfmtformats YAML the way Kubernetes manifests are usually written.opentofuprovidestofu fmtandtofu validatefor your Terraform files.
If you already have Node.js from another installer, such as nvm or fnm, leave
nodeout of the command.Step 3: Install the LazyVim starterBack up any Neovim setup you already have, then copy LazyVim's starter config into place.
Neovim keeps its settings in
~/.config/nvim, and its plugins, history and cache in three more folders. This moves any of them that already exist aside, with the date in the name, so nothing is lost:Terminal stamp=$(date +%Y%m%d-%H%M%S) for d in ~/.config/nvim ~/.local/share/nvim ~/.local/state/nvim ~/.cache/nvim; do [ -e "$d" ] && mv "$d" "$d.bak-$stamp" doneNow copy the starter config, then delete its Git history so the config is yours to change and track:
Terminal git clone https://github.com/LazyVim/starter ~/.config/nvim rm -rf ~/.config/nvim/.gitDo not start Neovim yet. The next steps finish the config first, so the first start installs everything in one go.
Step 4: Turn on the language extrasGo, TypeScript, Terraform, Docker, Helm, JSON and YAML support, plus a debugger, Harpoon, mini.files and mini.surround.
LazyVim keeps optional features, called extras, switched off until you ask for them. You can pick them one at a time with the
:LazyExtrascommand, which saves your choices tolazyvim.json. Writing that file yourself turns them all on at once:Terminal [ -f ~/.config/nvim/lazyvim.json ] && cp ~/.config/nvim/lazyvim.json ~/.config/nvim/lazyvim.json.bak-$(date +%Y%m%d-%H%M%S) cat > ~/.config/nvim/lazyvim.json <<'EOF' { "extras": [ "lazyvim.plugins.extras.coding.mini-surround", "lazyvim.plugins.extras.dap.core", "lazyvim.plugins.extras.editor.harpoon2", "lazyvim.plugins.extras.editor.mini-files", "lazyvim.plugins.extras.lang.docker", "lazyvim.plugins.extras.lang.go", "lazyvim.plugins.extras.lang.helm", "lazyvim.plugins.extras.lang.json", "lazyvim.plugins.extras.lang.terraform", "lazyvim.plugins.extras.lang.typescript", "lazyvim.plugins.extras.lang.yaml" ], "install_version": 8, "version": 8 } EOFWhat you get:
coding.mini-surround: keys to add, change and delete quotes and brackets around text.dap.core: a debugger with breakpoints and step-through.editor.harpoon2: pin a handful of files and jump between them with one key.editor.mini-files: a file browser you edit like a normal text buffer.lang.docker: Dockerfile and Compose language servers, plus the hadolint linter.lang.go: gopls, gofumpt, goimports and the Delve debugger.lang.helm: Helm chart templates.lang.json: JSON with schema checks.lang.terraform: the Terraform language server and the tflint linter.lang.typescript: the TypeScript and JavaScript language server.lang.yaml: YAML with schema checks, including Kubernetes manifests.
The two version numbers tell LazyVim this is a fresh install, so it uses its current defaults for file search and the file explorer.
Step 5: Set your options and keysWrap long lines, fold only when you ask, hide the tab line, and type jj or jk to leave insert mode.
LazyVim loads your own options from
lua/config/options.lua. Add three to the end of it:Terminal grep -q 'showtabline = 0' ~/.config/nvim/lua/config/options.lua || cat >> ~/.config/nvim/lua/config/options.lua <<'EOF' vim.opt.wrap = true -- wrap long lines instead of scrolling sideways vim.opt.foldmethod = "manual" -- fold only when you ask, with zf vim.opt.showtabline = 0 -- never show the tab line at the top EOFIn files it understands, LazyVim switches folding to follow the structure of the code, which would override the manual setting. This file stops that, so folds appear only where you make them:
Terminal [ -f ~/.config/nvim/lua/plugins/folds.lua ] && cp ~/.config/nvim/lua/plugins/folds.lua ~/.config/nvim/lua/plugins/folds.lua.bak-$(date +%Y%m%d-%H%M%S) cat > ~/.config/nvim/lua/plugins/folds.lua <<'EOF' -- Keep foldmethod = "manual" in every file return { { "nvim-treesitter/nvim-treesitter", opts = { folds = { enable = false } } }, { "neovim/nvim-lspconfig", opts = { folds = { enabled = false } } }, } EOFNext, make
jjandjkleave insert mode, so you can keep your hands on the home row instead of reaching forEsc:Terminal grep -q '"jj"' ~/.config/nvim/lua/config/keymaps.lua || cat >> ~/.config/nvim/lua/config/keymaps.lua <<'EOF' -- Leave insert mode by typing jj or jk vim.keymap.set("i", "jj", "<Esc>", { desc = "Leave insert mode" }) vim.keymap.set("i", "jk", "<Esc>", { desc = "Leave insert mode" }) EOFThe
grep -qchecks skip each append if it is already there, so running them twice is safe.Step 6: Make Tokyo Night transparent and drop the buffer tabsTokyo Night with a see-through background, so your Ghostty colors show through, and no row of open files along the top.
LazyVim already uses the Tokyo Night theme. This makes its background, side panels and pop-ups transparent, so the editor sits on your Ghostty background. It also turns off bufferline, the row of open files along the top:
Terminal [ -f ~/.config/nvim/lua/plugins/colorscheme.lua ] && cp ~/.config/nvim/lua/plugins/colorscheme.lua ~/.config/nvim/lua/plugins/colorscheme.lua.bak-$(date +%Y%m%d-%H%M%S) cat > ~/.config/nvim/lua/plugins/colorscheme.lua <<'EOF' return { { "LazyVim/LazyVim", opts = { colorscheme = "tokyonight", }, }, { "folke/tokyonight.nvim", opts = { transparent = true, styles = { sidebars = "transparent", floats = "transparent", }, }, }, } EOF [ -f ~/.config/nvim/lua/plugins/bufferline.lua ] && cp ~/.config/nvim/lua/plugins/bufferline.lua ~/.config/nvim/lua/plugins/bufferline.lua.bak-$(date +%Y%m%d-%H%M%S) cat > ~/.config/nvim/lua/plugins/bufferline.lua <<'EOF' return { { "akinsho/bufferline.nvim", enabled = false }, } EOFWithout the tabs you still switch between open files with
Shift+HandShift+L, or pick one from a list withSpacethen,.Step 7: Shorten the surround keysAdd and delete quotes and brackets around text with sa and sd.
The mini.surround extra adds, deletes and replaces pairs such as quotes and brackets. All its keys start with
gsby default. This shortens the two you will use most tosaandsd:Terminal [ -f ~/.config/nvim/lua/plugins/surround.lua ] && cp ~/.config/nvim/lua/plugins/surround.lua ~/.config/nvim/lua/plugins/surround.lua.bak-$(date +%Y%m%d-%H%M%S) cat > ~/.config/nvim/lua/plugins/surround.lua <<'EOF' return { "nvim-mini/mini.surround", opts = { mappings = { add = "sa", delete = "sd", find = "gsf", find_left = "gsF", highlight = "gsh", replace = "gsr", update_n_lines = "gsn", }, }, } EOFA few examples, with the cursor on a word:
Keys What it does saiw"Wrap the word in double quotes sd"Delete the double quotes around the cursor gsr"'Change double quotes to single quotes saiw)Wrap the word in parentheses Pressing
son its own still starts LazyVim's Flash jump after a short pause.Step 8: Format YAML for Kubernetes and Terraform with OpenTofuyamlfmt for YAML that matches Kubernetes manifests, and tofu fmt and tofu validate for Terraform files.
LazyVim formats a file every time you save it. The YAML extra's default formatter indents list items under their parent key, which Kubernetes manifests usually do not. This switches YAML to yamlfmt with lists kept flush with their key:
Terminal [ -f ~/.config/nvim/lua/plugins/conform.lua ] && cp ~/.config/nvim/lua/plugins/conform.lua ~/.config/nvim/lua/plugins/conform.lua.bak-$(date +%Y%m%d-%H%M%S) cat > ~/.config/nvim/lua/plugins/conform.lua <<'EOF' return { "stevearc/conform.nvim", opts = { formatters_by_ft = { yaml = { "yamlfmt" }, -- Kubernetes-friendly YAML }, formatters = { yamlfmt = { -- lists flush with their key, as kubectl writes them prepend_args = { "-formatter", "indentless_arrays=true" }, }, }, }, } EOFThe Terraform extra formats and checks files with the
terraformprogram. This points both at OpenTofu instead:Terminal [ -f ~/.config/nvim/lua/plugins/opentofu.lua ] && cp ~/.config/nvim/lua/plugins/opentofu.lua ~/.config/nvim/lua/plugins/opentofu.lua.bak-$(date +%Y%m%d-%H%M%S) cat > ~/.config/nvim/lua/plugins/opentofu.lua <<'EOF' return { { "stevearc/conform.nvim", opts = { formatters_by_ft = { terraform = { "tofu_fmt" }, tf = { "tofu_fmt" }, ["terraform-vars"] = { "tofu_fmt" }, }, }, }, { "mfussenegger/nvim-lint", opts = { linters_by_ft = { terraform = { "tofu" }, tf = { "tofu" }, }, }, }, } EOFGo needs nothing extra: the Go extra already turns on gofumpt formatting, automatic imports and staticcheck in gopls. To format without saving, press
Spacethencthenf.Step 9: Start Neovim for the first timeLazyVim installs every plugin, language server and parser on its own, then a health check confirms it all works.
Start Neovim:
Terminal nvimThe first start takes a minute or two. A window lists each plugin as it installs. When it finishes, press
qto close it. Mason, LazyVim's installer for language servers and formatters, keeps working in the background and reports each tool in the corner as it lands.Once the messages stop, quit with
:qaand startnvimagain, so everything loads cleanly. Then check that LazyVim has what it needs:Text :checkhealth lazyvimEvery line should start with OK. To see the language tools Mason installed, open its window with
:Mason, and pressqto close it.Step 10: Open Claude Code inside NeovimoptionalTurn on LazyVim's Claude Code extra to run Claude in a split that sees your open files and selections.
This step needs Claude Code, from the Claude Code guide. LazyVim has an extra for it, built on the claudecode.nvim plugin. Turn it on from inside Neovim:
- Type
:LazyExtrasand pressEnter. - Type
/claudecodeand pressEnterto jump toai.claudecode. - Press
xto turn it on, thenqto close the window. - Quit with
:qaand startnvimagain.
Every Claude key starts with
Spacethena:Keys What it does SpaceacOpen or close Claude in a split SpaceafMove the cursor into Claude's split SpaceabAdd the current file to the conversation SpaceasSend the selected lines, in visual mode SpacearPick an earlier conversation to resume SpaceaaAccept the change Claude proposes SpaceadReject the change Claude proposes When Claude wants to edit a file, Neovim shows the change as a side-by-side diff, and nothing is saved until you accept it.
- Type
Step 11: Neovim cheat sheetThe keys you will use every day in this setup.
LazyVim's leader key is
Space. Press it and wait, and a menu shows every key that can follow.Keys What it does jjorjkLeave insert mode SpaceSpaceFind a file by name Space/Search the text of every file SpaceeOpen or close the file explorer SpacefmBrowse the current folder with mini.files Space,Switch between open files Shift+H/Shift+LPrevious or next open file SpaceHPin the current file to Harpoon SpacehShow your pinned files Space1to9Jump to pinned file 1 to 9 gdGo to where a name is defined KShow the documentation for the name under the cursor SpacecaShow fixes and code actions SpacecfFormat the file SpaceggOpen lazygit SpacedbSet a breakpoint SpacedcStart or continue debugging SpaceskSearch every key binding SpaceqqQuit Neovim To change anything later, edit the files in
~/.config/nvim/lua/, then restart Neovim.