Configuring Neovim with Lua: Part 1

4 minute read


If you’re a Vim/Neovim user, you might be familiar with a Vim script which you would normally find at $HOME/.vimrc. This file can get pretty large and messy so in this part 1 of “Configuring Neovim with Lua”, I am going to walkthrough configuring Vim options with Lua.

File Placement

In Neovim, the initialization file or init file resides in the following path:


The way that I configure Neovim doesn’t require that we alter the init.lua file because our Vim options, keymaps, and plugins will reside in their own individual Lua files. Neovim looks for additional Lua configuration files in the following directory:


To keep things organized, I like to keep my Lua configuration files in a folder called profile:


In the profile directory, I have the following three files:

  1. options.lua: contains my Vim options
  2. keymaps.lua: contains my Vim keymaps
  3. plugins.lua: contains my Vim plugins which are managed by packer

In this blog, I’ll talk about setting Vim options in the options.lua file. In part 2, I’ll talk about creating keymappings and in part 3, I’ll provide a walkthrough for configuring pluggins with packer. Let’s go for it.

Setting up init.lua

As previously mentioned, we won’t be touching the init.lua file much, but it will contain references to our Lua files that actually contain configuration options. To do this, we will use Lua’s require keyword to import our Lua files. So the init.lua file should look like this:


require 'profile.plugins'
require 'profile.options'
require 'profile.keymaps'

So go ahead and create the following three files:


With our init.lua file now properly pointing to our additional Lua config files, we can go ahead and start adding configuration options to the options.lua file.

Configuring Vim Options

Popular Vim options, like the number option which tells Neovim to show line numbers, can be set through the vim.opt table. For example, setting the number option would require the following line of code to be placed in the options.lua file:

vim.opt.number = true

Now this is slightly more typing than I’d prefer but of couse because Lua is a programming language, we can use it like one. So to not have to repeatedly type vim.opt.* for every single option, we can use a little Lua-fu to make our lives easier:

local options = {
  number = true,
  relativenumber = true,
  ignorecase = true,
  encoding = "UTF-8",
  wrap = false,

for k, v in pairs(options) do
  vim.opt[k] = v

Using a Lua table called options, we can set options by creating key-value pairs - the key is the option name, and the value can be a string, boolean, integer, or even a table, for more complex values. Finally, we have a basic for-loop that iterates over the options table and sets the option via the vim.opt table. If you open up Neovim, you should see the enabled options:


Here is my personal options.lua file for reference:

local options = {
  backup = false,
  writebackup = false,
  swapfile = false,
  relativenumber = true,
  number = true,
  clipboard = "unnamedplus",
  ignorecase = true,
  undofile = true,
  undodir = string.format("%s/.undodir", vim.env.HOME),
  encoding = "UTF-8",
  pastetoggle = "<F2>",
  shiftwidth = 2,
  expandtab = true,
  hlsearch = true,
  wrap = false,
  cursorline = true,
  pumheight = 10,
  conceallevel = 0,
  tabstop = 2,
  cmdheight = 2,
  splitright = true,
  splitbelow = true,
  termguicolors = true,
  background = "dark",
  list = true,
  listchars = {
    eol = "$",
    trail = "+",
    tab = "> "
  shell = "/bin/bash",

for k,v in pairs(options) do
  vim.opt[k] = v

-- FZF
vim.env.FZF_DEFAULT_COMMAND = "rg --files --hidden --follow --no-ignore-vcs --fixed-strings"
vim.env.FZF_DEFAULT_OPTS = [[--ansi --preview-window 'right:60%' --layout reverse --margin=1,4 --bind ctrl-j:down,ctrl-k:up,ctrl-h:preview-down,ctrl-l:preview-up]]

-- Emmet
vim.g.user_emmet_leader_key = ","

-- Gitgutter
vim.g.gitgutter_git_executable = "/usr/bin/git"

-- VimGo
vim.g.go_highlight_structs = 1
vim.g.go_highlight_methods = 1
vim.g.go_highlight_functions = 1
vim.g.go_highlight_function_calls = 1
vim.g.go_highlight_function_parameters = 1
vim.g.go_highlight_operators = 1
vim.g.go_highlight_types = 1
vim.g.go_highlight_fields = 1
vim.g.go_highlight_build_constraints = 1
vim.g.go_highlight_generate_tags = 1
vim.g.go_highlight_format_strings = 1
vim.g.go_highlight_variable_declarations = 1
vim.g.go_highlight_variable_assignments = 1
vim.g.go_auto_type_info = 1
vim.g.go_fmt_autosave = 1
vim.g.go_mod_fmt_autosave = 1
vim.g.go_gopls_enabled = 1

-- Rust.vim
vim.g.rustfmt_autosave = 1

the following code alternates between the tokyonight
and papercolor colorschemes using even or odd numbers
math.randomseed(os.time()) --set seed to current time
local rand = math.random(1000)

if (rand % 2 == 0) then
  vim.g.tokyonight_style = "night"
  vim.cmd 'colorscheme tokyonight'
  vim.cmd 'colorscheme PaperColor'

As you can see, to set global Vimscript variables, you use the vim.g API; to set environment variables, you’d use the vim.env API; And lastly, if you’d like to directly execute Vimscript from within a Lua file, you’d have to the use the vim.cmd API.


You should now be able to continue to expand your options.lua file with your favorite options using the information you learned from this tutorial so have fun!

If you enjoyed reading this blog and learned something, keep an eye out for more of my posts and maybe consider following me on GitHub, where I work on cybersecurity projects. And if you are feeling really generous, consider buying me a coffee!

comments powered by Disqus