Neovim with Lua
The introduction of Lua as a first-class language in Neovim was a turning point for the entire ecosystem. Where Vimscript often felt like a language you endured, Lua is one you can genuinely enjoy -- it brings clean syntax, real data structures, and the kind of performance that makes complex configurations feel instant. If you've ever hit the limits of Vimscript or wondered how modern Neovim plugins achieve so much, this chapter will show you the foundation they're built on.
Neovim natively supports Lua as a first-class configuration language. Lua is faster, more readable, and provides access to the full Neovim API. This chapter covers everything you need to migrate from Vimscript to Lua.
What you'll learn in this chapter:
Set up an
init.luaand organize your Neovim configuration into modulesTranslate common Vimscript settings and mappings into Lua equivalents
Use
vim.apito create autocommands and user commands in LuaCall Vimscript functions and commands from Lua when needed
Why Lua?
Performance: Lua is significantly faster than Vimscript
Readability: Cleaner syntax, proper data structures, functions as first-class citizens
Ecosystem: The modern Neovim plugin ecosystem is built on Lua
API access: Full access to Neovim's API (
vim.api.*)LSP & Treesitter: Built-in features are configured in Lua
Getting Started: init.lua
Neovim looks for configuration in this order:
~/.config/nvim/init.lua~/.config/nvim/init.vim
You can only have one (see Chapter 10: Configuring Vim & Neovim for Vimscript-based configuration). To start with Lua:
Project Structure
A well-organized Neovim config:
Your init.lua then just requires these modules (the plugins/ directory is managed by lazy.nvim -- see Chapter 12: Plugin Management):
Setting Options: vim.opt
The vim.opt table replaces :set commands:
Vimscript to Lua Translation
set number
vim.opt.number = true
set nonumber
vim.opt.number = false
set shiftwidth=4
vim.opt.shiftwidth = 4
set path+=**
vim.opt.path:append('**')
let g:mapleader = ' '
vim.g.mapleader = ' '
let b:var = 1
vim.b.var = 1
Key Mappings: vim.keymap.set
Options for vim.keymap.set
noremap
true
Non-recursive mapping
silent
false
Don't show command in command line
desc
nil
Description (shows in which-key)
buffer
nil
Buffer-local mapping
expr
false
Mapping is an expression
remap
false
Allow recursive mapping
Autocommands: vim.api.nvim_create_autocmd
User Commands: vim.api.nvim_create_user_command
Useful Vim API Functions
Calling Vimscript from Lua
You can always fall back to Vimscript when needed (for more advanced scripting techniques, see Chapter 21: Scripting):
Summary
Lua is the modern foundation for Neovim configuration. By using vim.opt for settings, vim.keymap.set for mappings, and vim.api for autocommands and user commands, you gain cleaner syntax, better performance, and full access to Neovim's API. A well-organized init.lua with modular files keeps your configuration maintainable as it grows.
Key takeaways:
vim.optreplaces:set,vim.greplaces:let g:, andvim.keymap.setreplaces:map-- all with better ergonomics and type safety.Organize your configuration into separate modules (
options.lua,keymaps.lua,autocmds.lua) loaded from a centralinit.lua.vim.api.nvim_create_autocmdandvim.api.nvim_create_user_commandprovide structured, Lua-native alternatives to Vimscript autocommands and commands.You can always call Vimscript from Lua using
vim.cmdorvim.fnwhen a Lua equivalent is not available.
Exercises
Create an init.lua from scratch -- Back up your existing configuration. Create a new
~/.config/nvim/init.luathat setsnumber,relativenumber,expandtab,shiftwidth=4, andtermguicolorsusingvim.opt.Define key mappings in Lua -- Set the leader key to space, then create mappings to save the current file with
<leader>wand to clear search highlights with<Esc>.Convert a Vimscript autocommand to Lua -- Take the following Vimscript and rewrite it in Lua using
vim.api.nvim_create_autocmd:Create a custom user command -- Write a Lua user command called
:Todaythat inserts the current date on the line below the cursor.Use vim.fn to call a Vimscript function -- Write a Lua snippet that uses
vim.fn.expandto print the full path of the current file andvim.fn.lineto print the total number of lines.
Last updated
Was this helpful?