Neovim
Back to Development
NeovimIntermediate22 min

Neovim Lua Configuration Guide 2026: Setup from Scratch with lazy.nvim

Why Lua Config in 2026?

Neovim's Lua API is the biggest reason to switch from Vim. Unlike Vimscript, Lua is a real programming language — fast, composable, and with first-class support in Neovim 0.10+.

This guide builds a Neovim config from zero using lazy.nvim, the modern plugin manager that loads plugins on-demand for instant startup.

By the end, you'll have a config that boots in under 50ms and rivals any IDE.

Installing Neovim from Scratch

Install Neovim 0.10 or later. On macOS: brew install neovim. On Linux: use your distro's package manager or build from source.

Tip: Install a Nerd Font like JetBrains Mono or FiraCode before starting. Without it, plugin icons will show as boxes.

Create the config directory structure:

~/.config/nvim/
├── init.lua          # Entry point
├── lua/
│   ├── core/         # Options, keymaps, autocmds
│   │   ├── init.lua
│   │   ├── options.lua
│   │   └── keymaps.lua
│   └── plugins/      # Plugin specs
│       └── init.lua

Bootstrapping lazy.nvim

The magic of lazy.nvim is that it bootstraps itself. Put this in init.lua and lazy.nvim installs itself on first launch:

-- bootstrap lazy.nvim
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", lazypath
})
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup("lua/plugins")

Now create plugin specs in lua/plugins/. Each file returns a table — lazy.nvim loads them automatically:

-- lua/plugins/telescope.lua
return {
"nvim-telescope/telescope.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
keys = {
{ "ff", "Telescope find_files", desc = "Find files" },
{ "fg", "Telescope live_grep", desc = "Live grep" },
},
}

Plugin Structure & Specs

The key to a great config is modular keymaps. Put your keybindings in lua/core/keymaps.lua and require them from init.lua.

Set core options in lua/core/options.lua:

vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.tabstop = 2
vim.opt.shiftwidth = 2
vim.opt.termguicolors = true
vim.opt.scrolloff = 8
vim.opt.signcolumn = "yes"

Keymaps, Options & Autocmds

Once your base config is solid, add these power-user touches:

Pro tip: Run :Lazy profile to see which plugins slow down startup. Target under 50ms total.

Config Errors & Linter

Common config issues and fixes:

Your Config is a Living Project

Your Neovim config is now a living project. Here's what to explore:

← PreviousRaycast Script Commands Tutorial: Automate macOS Workflows with Shell ScriptsNext →Hammerspoon Window Management Guide: macOS Layouts and Snapping with Lua