Neovim — init.lua

Overview
Integration of Lua as a first-class language in the latest release of Neovim provides a good alternative to developers to use a more proper programming language to configure Neovim and develop plugins. Vimscript can get a bit messy to manage when the code base grows. Lua is also relatively easy to learn compared to Emacs Lisp which is used to configure Emacs.
I have been trying to configure Neovim using Lua. There are many developers who had done this, and it seems each one has very different ways of coding the configurations. This is a bit challenging for a beginner to understand.
In this article, I am going to set up a very simple solution that hopefully is easier for beginners to understand, and they can further engineer or custom the solution based on their preferences.
What to Achieve
- Automate the installation and setup of a package manager -
packer.nvim
- Use
packer.nvim
to install a color scheme, fuzzy finder, and Lua language server - Set up sensible defaults and key mappings using Lua
- Configure Lua language server so that I can use Neovim to learn Lua
And below is the init.lua
I am going to configure. Once you have an idea of how this can be set up, you should be able to custom or refactor it to suit your needs.

Learn the Basics of Lua
Lua is a relatively easy language to learn and understand. I strongly suggest you to spend 30 minutes to 1 hour to go through the followings
You need some basics, e.g.
- not equal is
~=
- string can be single-quoted, double-quoted or included in
[[ ]]
- how to write a module and invoke it
- etc…
This will help you to understand for examples commands shown below. Both values highlighted in bold below are valid Lua strings.
vim.cmd [[packadd packer.nvim]]
vim.cmd 'autocmd BufWritePost plugins.lua PackerCompile'
NeoVim Lua Basics
Global, Buffer, and Window Scoped Options
Within Neovim, type :h vim.o
and you can see the defined Lua tables for vim options.

Using Vimscript normally we do not differentiate the option scope but if you read the Vim documentation you can see that for each option normally there is a scope defined. E.g. for hidden
it is a global option.

hidden
Global OptionUsing the current Neovim release, when defining the option we need to explicitly define the scope. We will see how to do this later. This may change in the future release of Neovim.
Lua-Vimscript Bridge
Type :h lua-vimscript
and you can see the defined interfaces to Vimscript and variables. Specifically vim.call
, vim.cmd
, vim.fn
can be used to invoke Vim functions and commands.

Lua Vim Variables
Type :h lua-vim-variables
and you can see how to access Vim editor global dictionaries g: w: b: t: v: c. E.g. vim.g
for the global editor variables.

And if you want to read the full documentation, just type :h lua
.
Configure Startup Options
With the basics, let’s get started to configure Neovim using Lua.
Normally init.lua
is under $HOME/.config/nvim
(for Linux and macOS), but you can use XDG_CONFIG_HOME to specify a different folder.
Leader Key
For my preference, I will map the leader key to Space.
-- Map leader to space
vim.g.mapleader = ' '
utils Module
I am going to define a Lua module called utils
which helps to define the Vim options and mappings.

- Create a folder called
utils
under thelua
folder. - Create a file called
init.lua
underutils
folder
A folder containing an init.lua
file can be required directly, without having to specify the name of the file.
And below is the code snippet for init.lua
for the utils
module.
This module just defines 2 functions — 1 to set the option either at global, buffer, or window scope, another one to set the key mapping.
Settings
Create a file called settings.lua
under lua
folder with the following content.
- The
utils
module is required or imported at the top of the file vim.cmd
is used to run Vim commandsutils.opt
helper function is used to set various Vim options at global, buffer, and window scopes.
With the settings configured, I need to requiresettings.lua
from the main init.lua.
Here is how the code looks like in the main init.lua
-- Map leader to space
vim.g.mapleader = ' 'local fn = vim.fn
local execute = vim.api.nvim_command-- Sensible defaults
require('settings')
Note: Lua files will not be sourced automatically. You need to explicitly require them.
Configure Key Mappings
Configuring key mappings is similar to configuring Vim options.
Create a file called keymappings.lua
under the lua
folder.
local utils = require('utils')utils.map('n', '<C-l>', '<cmd>noh<CR>') -- Clear highlights
utils.map('i', 'jk', '<Esc>') -- jk to escape
There are only a few mappings defined. You can add and modify according to your needs.
In maininit.lua
file you need to import the mapping file.
-- Key mappings
require('keymappings')
Configure Package Manager
I am going to set up packer.nvim. You can definitely use other package managers which you prefer, e.g. paq.nvim.
Setting up packer.nvim is relatively easy.
Auto Install packer.nvim
In the main init.lua
file, the below code snippet should automate the installation of packer.nvim
-- Auto install packer.nvim if not exists
local install_path = fn.stdpath('data')..'/site/pack/packer/opt/packer.nvim'
if fn.empty(fn.glob(install_path)) > 0 then
execute('!git clone https://github.com/wbthomason/packer.nvim '..install_path)
end
vim.cmd [[packadd packer.nvim]]
vim.cmd 'autocmd BufWritePost plugins.lua PackerCompile' -- Auto compile when there are changes in plugins.lua
The autocmd
is used to compile plugins.lua
whenever the file is saved. More on this later.
Now restart Neovim and the package manager should get installed automatically.
plugins.lua
Create a file called plugins.lua
under the lua
folder.
Plugins I installed
gruvbox-material
for the color schemetelescope.nvim
for fuzzy finding- Few LSP plugins for Lua
vim-dispatch
andvim-fugitive
for Git integration
Save and source the file by running :luafile %
and then :PackerInstall
to install them. This file is automatically compiled using the autocmd
specified previously.
We will see how to configure these plugins in the next section.
Configure Plugins
telescope.nvim
You can mix and match Vimscript and Lua files for your configuration.
For telescope.nvim
, let’s use a .vim file to configure the key mappings.
Create a file called telescope.vim
either in the plugin
or after/plugin
folder. In my case, I created the file under plugin
folder.
" Find files using Telescope command-line sugar.
nnoremap <leader>ff <cmd>Telescope find_files<cr>
nnoremap <leader>fg <cmd>Telescope live_grep<cr>
nnoremap <leader>fb <cmd>Telescope buffers<cr>
nnoremap <leader>fh <cmd>Telescope help_tags<cr>
Unlike Lua files, Vimscript files under these folders are sourced automatically.
Now I can press <Leader>ff
to find files.

Lua LSP
For Lua LSP, I will create a folder to configure it. Later we will see another way to configure the remaining plugins.
- Create a folder called
lsp_lua
under thelua
folder. - Create a file called
init.lua
underlsp_lua
folder (Remember a folder withinit.lua
can be required directly without specifying the file name)
You can refer to the following links on the Lua LSP setup.
- nlua.nvim for Lua Development
- nvim-lspconfig for Lua LSP
Lua Language Server
The Lua language server used is sumneko_lua and I need to install it manually.
Follow the instructions here to install it based on your operating system. In my case, I installed it under $HOME/.cache/nvim/nlua/sumneko_lua/
which is the default folder expected by Neovim LSP.
Tip: Use :LspInfo
to validate LSP setup. It will tell you if the language server is installed and configured correctly.

With the LSP and language server set up correctly, now I can write Lua code in Neovim.


Color Scheme, Fugitive and Code Completion
For these plugins, let’s group the configurations in a folder.
Create a folder called config
under lua
folder.
I created 3 files called colorscheme.lua
, completion.lua
and fugitive.lua
to configure the respective plugins.
colorscheme.lua
local utils = require('utils')
local cmd = vim.cmdutils.opt('o', 'termguicolors', true)
cmd 'colorscheme gruvbox-material'
completion.lua
local utils = require('utils')utils.opt('o', 'completeopt', 'menuone,noinsert,noselect')
vim.cmd [[set shortmess+=c]]
vim.g.completion_confirm_key = ""
vim.g.completion_matching_strategy_list = {'exact', 'substring', 'fuzzy'}-- <Tab> to navigate the completion menu
utils.map('i', '<S-Tab>', 'pumvisible() ? "\\<C-p>" : "\\<Tab>"', {expr = true})
utils.map('i', '<Tab>', 'pumvisible() ? "\\<C-n>" : "\\<Tab>"', {expr = true})
fugitive.lua
local utils = require('utils')utils.map('n', '<Leader>gs', '<cmd>Gstatus<CR>') -- Git status
Since Lua files are not sourced automatically, I have 2 options to import these settings.
- Require the Lua files individually in the main
init.lua
- Create an
init.lua
file underconfig
folder and only require theconfig
once.
In my case I created init.lua
under config
folder.
require('config.colorscheme')
require('config.completion')
require('config.fugitive')
And in the main init.lua
I added the following line.
-- Another option is to groups configuration in one folder
require('config')-- OR you can invoke them individually here
--require('config.colorscheme') -- color scheme
--require('config.completion') -- completion
--require('config.fugitive') -- fugitive
The full listing of the main init.lua
.
Summary
Configure Neovim using Lua is relatively easy once you get the hang of it. I believe with the integration of Lua into Neovim is definitely going to help grow the community to explore the full potential of Vim.
You can find the source code I used from this repository.
Read this article to see how I leverage this configuration to configure LSP and DAP using Lua.
Do also check out the following articles.
Neovim LSP Enhanced
Additional features to enhance your LSP experience in Neovim.
alpha2phi.medium.com