Migrating Your Neovim Config from Vimscript to Lua: A Step‑by‑Step Guide
Switch from a Vimscript <code>vimrc</code> to a Lua <code>init.lua</code> in Neovim. This guide walks through the steps, shows example conversions, validates settings, and covers recovery options for a smooth transition.
10 Aug 2025, 14:06 UTC

Desired Outcome
Transitioning from a vimrc to an init.lua gives you faster startup, type‑safe key‑mapping, native access to Neovim APIs, and a cleaner, more maintainable configuration. The end result is a Lua‑based config that loads in under 100 ms on most machines and can call plugin functions directly via require.
What You’ll Get
- Lua syntax for options, mappings, and plugins.
- Structured modules so
init.luastays minimal. - Runtime error handling with
pcallandvim.notify. - Built‑in terminal control via
vim.fn.termopen.
Prerequisites
- Neovim 0.7+ – Lua support is baked in from this version.
- Basic Lua knowledge (tables, functions,
require). - Backup of your current
~/.config/nvim/init.vimor~/.vimrc. The migration can be reverted by restoring this file. - Optional:
checkhealth luato confirm Lua runtime is available.
Step‑by‑Step Conversion
1. Rename and Create init.lua
# In your shell
mv ~/.config/nvim/init.vim ~/.config/nvim/init.vim.bak
# Create the new file
touch ~/.config/nvim/init.lua
2. Migrate Basic Settings
Vimscript set number becomes vim.opt.number = true in Lua. Use vim.opt for all options.
-- init.lua
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.wrap = false
3. Convert Mappings
Replace nnoremap with vim.keymap.set for type safety.
-- Old Vimscript
nnoremap <C-n> :NvimTreeToggle<CR>
-- New Lua
vim.keymap.set('n', '<C-n>', ':NvimTreeToggle<CR>', {noremap=true, silent=true})
4. Port Plugin Configuration
Many plugins expose a setup table. For example, nvim-treesitter:
require('nvim-treesitter.configs').setup {
highlight = { enable = true },
indent = { enable = true }
}
5. Organize into Modules
Keep init.lua lightweight by creating a lua/user package.
# Directory layout
~/.config/nvim/lua/user/core.lua
~/.config/nvim/lua/user/mappings.lua
~/.config/nvim/lua/user/plugins.lua
# init.lua
require('user.core')
require('user.mappings')
require('user.plugins')
6. Test with :luafile
During migration, open a scratch buffer and run :luafile % to validate snippets before saving.
Validation Checks
Startup Health
nvim --headless -c 'checkhealth lua' -c 'qa!'
Look for lua: OK in the output.
Settings Take Effect
nvim -c 'set number? | qa!'
Output should be number followed by on.
Plugin API Calls
nvim -c 'lua require("nvim-treesitter.configs").setup({})' -c 'qa!'
No error messages in :messages mean success.
Keymaps Work
nvim -c 'verbose map <C-n>' -c 'qa!'
Output should reference :NvimTreeToggle.
Recovery Options
Revert to vimrc
Delete init.lua and rename the backup:
rm ~/.config/nvim/init.lua
mv ~/.config/nvim/init.vim.bak ~/.config/nvim/init.vim
Graceful Failure of Optional Modules
Wrap require in pcall and notify on error.
local ok, err = pcall(require, 'user.optional')
if not ok then
vim.notify('Optional module failed: ' .. err, vim.log.levels.WARN)
end
Practical Example
Converting a simple vimrc snippet that sets options, defines a mapping, and loads a plugin:
# Vimscript (old)
set number
set relativenumber
nnoremap <C-f> :Files<CR>
Plug 'junegunn/fzf.vim'
# Lua (new)
-- init.lua
vim.opt.number = true
vim.opt.relativenumber = true
vim.keymap.set('n', '<C-f>', ':Files<CR>', {noremap=true, silent=true})
require('fzf').setup()
Limitations & Notes
- Lua is case‑sensitive;
require('User')is different fromrequire('user'). - Legacy Vimscript plugins that rely on global variables may need
vim.g.varname = valuein Lua. - Some options expect strings; use
vim.opt.shortmess = 'filnxtO'instead of a table. - Errors in
init.luastop Neovim from launching; always test snippets with:luafile %before reloading.
Conclusion
By following the steps above, you’ll convert a functional vimrc into a modern, maintainable Lua configuration. The process is iterative—test, validate, and rollback if needed. Once complete, you’ll enjoy faster startup, clearer code, and direct access to Neovim’s powerful Lua APIs.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.