Neovim — init.lua

Neovim + Lua = init.lua


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

  • 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.

Neovim Setup with Lua LSP

Learn the Basics of Lua

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


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.

Vim hidden Global Option

Using 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


Lua Vim Variables


And if you want to read the full documentation, just type :h lua.

Configure Startup Options

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

-- Map leader to space
vim.g.mapleader = ' '

utils Module

  • Create a folder called utils under the lua folder.
  • Create a file called init.lua under utils 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.


  • The utils module is required or imported at the top of the file
  • vim.cmd is used to run Vim commands
  • utils.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

Note: Lua files will not be sourced automatically. You need to explicitly require them.

Configure Key Mappings

Create a file called keymappings.lua under the lua folder.

local utils = require('utils')'n', '<C-l>', '<cmd>noh<CR>') -- Clear highlights'i', 'jk', '<Esc>') -- jk to escape

There are only a few mappings defined. You can add and modify according to your needs.

In maininit.luafile you need to import the mapping file.

-- Key mappings

Configure Package Manager

Setting up packer.nvim is relatively easy.

Auto Install 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 '..install_path)
vim.cmd [[packadd packer.nvim]]
vim.cmd 'autocmd BufWritePost plugins.lua PackerCompile' -- Auto compile when there are changes in plugins.lua

The autocmdis 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 I installed

  • gruvbox-material for the color scheme
  • telescope.nvim for fuzzy finding
  • Few LSP plugins for Lua
  • vim-dispatch and vim-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


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.



  • Create a folder called lsp_lua under the lua folder.
  • Create a file called init.lua under lsp_lua folder (Remember a folder with init.lua can be required directly without specifying the file name)

You can refer to the following links on the Lua LSP setup.

Lua Language Server

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.

LspInfo Screen

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

Neovim Lua LSP

Color Scheme, Fugitive and Code Completion

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.


local utils = require('utils')
local cmd = vim.cmd
utils.opt('o', 'termguicolors', true)
cmd 'colorscheme gruvbox-material'


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'i', '<S-Tab>', 'pumvisible() ? "\\<C-p>" : "\\<Tab>"', {expr = true})'i', '<Tab>', 'pumvisible() ? "\\<C-n>" : "\\<Tab>"', {expr = true})


local utils = require('utils')'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 under config folder and only require the config once.

In my case I created init.lua under config folder.


And in the main init.lua I added the following line.

-- Another option is to groups configuration in one folder
-- 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.

Main init.lua


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.


Programmer and occasional blogger.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store