My Neovim Configuration
Here you will find the structure and configuration of the Neovim setup I implemented
Why use Lua to configure Neovim?
Directory Structure
The Neovim structure with Lua follows a modular pattern that separates settings by category:
- init.lua
- lazy-lock.json
- .luarc.json
Directorylua/
Directoryconfig/
- autocmds.lua
- keymaps.lua
- lazy.lua
- options.lua
- theme.lua
Directoryplugins/
- init.lua
Directorygit-manager/
- …
Directoryinterface/
- …
Directorylsp/
- …
Directorymarkdown/
- …
Directoryprogramming/
- …
Main File: init.lua
init.lua is the entry point of the configuration. It should be minimal, delegating the work to smaller modules:
-- Enables the Lua module cache (huge startup gain on Neovim 0.9+).if vim.loader and vim.loader.enable then vim.loader.enable()end
-- Leader keys must be set before any plugin spec is loaded.vim.g.mapleader = " "vim.g.maplocalleader = " "
-- Loads the configuration modules.require("config.options")require("config.lazy")require("config.keymaps")require("config.autocmds")Why this order?
- options first: Basic settings that do not depend on plugins
- lazy next: The plugin manager must be loaded before the plugins
- keymaps: Mappings that work without specific plugins
- autocmds: Events that depend on other settings
Configuration Modules (lua/config/)
options.lua
Pure Neovim settings that do not require plugins:
local opt = vim.opt
-- Indentationopt.expandtab = true -- converts tabs to spacesopt.tabstop = 2 -- visual width of a tabopt.softtabstop = 2 -- spaces inserted when pressing <Tab>opt.shiftwidth = 2 -- spaces used for auto-indentopt.autoindent = true -- copies indent from the current lineopt.smartindent = true -- smart indentation for new lines
-- UIopt.number = true -- shows absolute line numbersopt.relativenumber = false -- set to true for hybrid numbersopt.cursorline = true -- highlights the current lineopt.signcolumn = "yes" -- always renders the sign columnopt.termguicolors = true -- 24-bit colorsopt.showmode = false -- the mode is shown by lualinelazy.lua
Bootstrap of the lazy.nvim plugin manager:
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"if not (vim.uv or vim.loop).fs_stat(lazypath) then vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", "--branch=stable", lazypath, })endvim.opt.rtp:prepend(lazypath)
require("lazy").setup({ spec = { { import = "plugins" }, -- Imports all plugins from lua/plugins/ }, defaults = { lazy = false, -- plugins opt in to lazy loading version = false, -- always uses the latest commit }, performance = { cache = { enabled = true }, rtp = { disabled_plugins = { "gzip", "tarPlugin", "tohtml", "tutor", "zipPlugin", "netrwPlugin", "matchit", "matchparen", "spellfile", }, }, },})keymaps.lua
Global mappings that do not depend on specific plugins:
local map = function(mode, lhs, rhs, opts) opts = vim.tbl_extend("force", { silent = true }, opts or {}) vim.keymap.set(mode, lhs, rhs, opts)end
-- Window navigationmap("n", "<C-h>", "<C-w>h", { desc = "Window: move left" })map("n", "<C-j>", "<C-w>j", { desc = "Window: move down" })map("n", "<C-k>", "<C-w>k", { desc = "Window: move up" })map("n", "<C-l>", "<C-w>l", { desc = "Window: move right" })
-- Clear search highlightmap("n", "<Esc>", "<cmd>nohlsearch<cr>", { desc = "Clear search highlight" })autocmds.lua
Lightweight autocommands for Neovim events:
-- Briefly highlights the yanked regionvim.api.nvim_create_autocmd("TextYankPost", { group = augroup("highlight_yank"), callback = function() vim.highlight.on_yank({ timeout = 150 }) end,})
-- Removes trailing whitespace on save (except markdown)vim.api.nvim_create_autocmd("BufWritePre", { group = augroup("trim_whitespace"), callback = function() if vim.bo.filetype == "markdown" or vim.bo.filetype == "mdx" then return end local save = vim.fn.winsaveview() vim.cmd([[keepjumps %s/\s\+$//e]]) vim.fn.winrestview(save) end,})theme.lua
Shared color palette used by all plugins:
return { -- Backgrounds bg = "#0d0d0d", -- primary background bg_alt = "#0d0d0d", -- elevated surfaces bg_float = "#0d0d0d", -- floating windows
-- Foregrounds fg = "#c9d1d9", -- primary text fg_strong = "#e6edf3", -- titles, focused elements fg_muted = "#6e7681", -- comments, hints
-- Semantic accents green = "#3fb950", -- success, additions blue = "#58a6ff", -- info, links orange = "#e8912d", -- warnings red = "#ff7b72", -- errors, deletions yellow = "#d29922", -- caution, modifications purple = "#bc8cff", -- C# / .NET accent}Plugin System (lua/plugins/)
plugins/init.lua
Loader that imports the plugin groups:
return { { import = "plugins.interface" }, { import = "plugins.lsp" }, { import = "plugins.markdown" }, { import = "plugins.programming" }, { import = "plugins.git-manager" },}Organization by Category
Each category is a directory with an individual .lua file for each plugin:
- interface/: UI plugins (telescope, neotree, dashboard, etc.)
- lsp/: LSP plugins (nvim-lspconfig, mason, nvim-dap)
- programming/: Development plugins (cmp, neotest, comment, etc.)
- git-manager/: Git plugins (gitsigns, lazygit)
- markdown/: Markdown-specific plugins
How to Configure Neovim to Read Lua Files
-
Create the configuration directory
Creating the directory on Windows mkdir $env:LOCALAPPDATA\nvimCreating the directory on Linux mkdir -p ~/.config/nvim -
Create the init.lua file
Creating init.lua on Windows New-Item -Path "$env:LOCALAPPDATA\nvim\init.lua" -ItemType FileCreating init.lua on Linux touch ~/.config/nvim/init.lua -
Add the directory structure
Creating the structure on Windows mkdir $env:LOCALAPPDATA\nvim\luamkdir $env:LOCALAPPDATA\nvim\lua\configmkdir $env:LOCALAPPDATA\nvim\lua\pluginsCreating the structure on Linux mkdir -p ~/.config/nvim/lua/configmkdir -p ~/.config/nvim/lua/plugins -
Copy the configuration files
Copy the files from your Neovim repository into the corresponding directories.
-
Restart Neovim
Restarting Neovim nvimlazy.nvim will automatically install the plugins on the first run.