Banner of The Ultimate Neovim Configuration: A Modular, Reproducible Developer Environment

The Ultimate Neovim Configuration: A Modular, Reproducible Developer Environment


Category: vim

📅 May 29, 2026   |   👁️ Views: 45

Author:   mosaid

Why “Ultimate”? A Philosophy, Not a Dump of Settings Top

An ultimate Neovim configuration isn’t the one with the most plugins—it’s the one that starts in under 100 ms, behaves identically on any machine, and feels like a custom‑built engineering console rather than a text editor. This article presents the full architecture of the setup I’ve refined over years of daily use: writing LaTeX, Python, shell scripts, HTML, and Markdown. It’s modular, lazy‑loaded, and completely deterministic. Download the included zip file at the end of the article, run :Lazy sync, and every keybinding, colour, and snippet is exactly as intended.

The configuration is split into logical modules—each file has a single responsibility. This article walks through every piece, explaining not just the “what” but the “why”. All file contents are included; copy them directly into your own ~/.config/nvim and you’ll have a fully functional developer environment.

Directory Tree Top

Neovim respects ~/.config/nvim/ and expects Lua modules under lua/. The tree below shows every file that makes up this configuration. Central files are highlighted in bold.

~/.config/nvim/
├── init.lua                         ← entry point
├── lazy-lock.json                   ← pinned plugin versions
├── lua/
│   ├── config/
│   │   ├── lazy.lua                 ← bootstraps lazy.nvim
│   │   ├── colors.lua               ← themes & highlights
│   │   ├── commands.lua             ← user commands
│   │   ├── functions.lua            ← automation utilities
│   │   ├── keymaps.lua              ← global keybindings
│   │   ├── html_markdown_maps.lua   ← shared visual wrappers
│   │   ├── html_snippets.lua        ← HTML / Markdown snippets
│   │   ├── tex_snippets.lua         ← LaTeX snippets
│   │   └── options.lua
│   └── plugins/
│       └── core.lua                 ← plugin specification
└── ftplugin/
    ├── python.lua
    ├── tex.lua
    ├── html.lua
    ├── markdown.lua
    └── lua.lua
    

Nothing is loaded until it’s needed. Global options live in init.lua; everything else is deferred by lazy.nvim or triggered by filetype events.

The Bootstrapper — init.lua Top

init.lua is the first file Neovim reads. It sets the baseline: leader keys, editor options, persistent history and undo, a fallback colourscheme, and the lazy‑loading schedule.

Here is the complete file.


-- Leader keys
vim.g.mapleader = ","
vim.g.maplocalleader = " "

-- Basic settings
vim.o.number = true
vim.o.relativenumber = true
vim.o.termguicolors = true
vim.o.wrap = true
vim.o.tabstop = 2
vim.o.shiftwidth = 2
vim.o.expandtab = true
vim.o.mouse = "a"
vim.o.cmdheight = 1
vim.opt.ignorecase = true
vim.opt.smartcase = true

-- Disable netrw (we use ranger / telescope)
vim.g.loaded_netrw = 1
vim.g.loaded_netrwPlugin = 1

-- Maximum history and persistent undo
vim.opt.history = 10000
vim.opt.undolevels = 10000
vim.opt.undoreload = 100000
vim.opt.undofile = true
vim.opt.undodir = vim.fn.stdpath("data") .. "/undo"
vim.opt.shadafile = vim.fn.stdpath("data") .. "/shada/main.shada"
vim.opt.shada = "'100000,<1000,s100,h"
vim.cmd("silent! rshada")

-- Fallback colourscheme – editor never looks broken
vim.cmd("colorscheme desert")

-- Bootstrap lazy.nvim, then schedule the rest
require("config.lazy")
vim.schedule(function()
  require("config.colors").setup()
  require("config.keymaps")
  require("config.commands")
end)

-- Autocommands
-- Remove trailing whitespace on save
vim.api.nvim_create_autocmd("BufWritePre", {
  pattern = "*",
  callback = function()
    vim.cmd([[%s/\s\+$//e]])
  end
})

-- Remember last cursor position
vim.api.nvim_create_autocmd("BufReadPost", {
  pattern = "*",
  callback = function()
    local last_pos = vim.fn.line([['"]])
    if last_pos > 1 and last_pos <= vim.fn.line("$") then
      vim.cmd("normal! g`\"")
    end
  end,
})

-- Automatically set filetype for .tex files
vim.api.nvim_create_autocmd({"BufEnter", "BufNew", "BufNewFile", "BufRead"}, {
  pattern = "*.tex",
  callback = function()
    vim.bo.filetype = "tex"
  end
})

-- Change current directory to the directory of the current file (except /tmp)
vim.api.nvim_create_autocmd("BufReadPost", {
  callback = function()
    local dir = vim.fn.expand("%:p:h")
    if dir ~= "" and not dir:match("^/tmp") then
      vim.cmd("silent! lcd " .. dir)
    end
  end,
})

-- Briefly highlight yanked text
vim.api.nvim_create_autocmd("TextYankPost", {
  pattern = "*",
  callback = function()
    vim.highlight.on_yank({
      higroup = "IncSearch",
      timeout = 500,
    })
  end,
})

    
  • Leader keys, for global, Space for local – keep custom mappings under the left hand.
  • Persistent state – undo files and shada (command/search history, marks) are stored in Neovim’s data directory and set to very high limits so nothing is ever lost.
  • Fallback colourschemedesert is set synchronously to eliminate any flash of unstyled text. The real theme loads later.
  • Scheduled callbackvim.schedule() defers the remaining setup until after plugins are loaded, preventing “module not found” errors.
  • Autocommands – small infrastructure pieces that keep diffs clean, restore cursor position, auto‑detect .tex files, and provide instant yank feedback.

Lazy Loading with lazy.nvim Top

lua/config/lazy.lua is the only file that touches plugin management. It clones lazy.nvim if missing, then loads the plugin specification from lua/plugins/core.lua.


local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    "git", "clone", "--filter=blob:none",
    "https://github.com/folke/lazy.nvim.git", lazypath,
  })
end
vim.opt.rtp:prepend(lazypath)

require("lazy").setup({
  spec = { { import = "plugins" } },
  ui = { border = "rounded" },
})

    

The companion lazy-lock.json (included in the zip file at the end of the article) pins every plugin commit, making the whole plugin set reproducible.

The Visual Stack — colors.lua Top

lua/config/colors.lua applies the chosen theme (Nordic), sets custom highlights, makes most UI elements transparent, and re‑applies critical highlights after every colour scheme change.


local M = {}
function M.setup()
  vim.o.background = "dark"
  local ok, err = pcall(vim.cmd, "colorscheme nordic")
  if not ok then
    vim.cmd("colorscheme desert")
    vim.notify("Warning: Falling back to 'desert'. " .. tostring(err), vim.log.levels.WARN)
  end
  vim.wo.cursorline = true

  -- Explicit hex colours (independent of theme palette)
  vim.api.nvim_set_hl(0, "CursorLine",   { bg = "#3b4261", bold = true })
  vim.api.nvim_set_hl(0, "Cursor",       { bg = "#434C5E", fg = "#ECEFF4", blend = 60 })
  vim.api.nvim_set_hl(0, "StatusLine",   { bg = "#1f2335", fg = "#c0caf5", bold = true })
  vim.api.nvim_set_hl(0, "Visual",       { bg = "#FFD966", fg = "black" })
  vim.api.nvim_set_hl(0, "Search",       { bg = "#ff9e64", fg = "black", bold = true })
  vim.api.nvim_set_hl(0, "LineNr",       { fg = "#FFFF00" })
  vim.api.nvim_set_hl(0, "CursorLineNr", { fg = "#c0caf5", bold = true })
  -- … plus many more (see the full file)

  -- Transparency: structural UI gets no background
  local transparent = {
    "Normal", "NormalNC", "NormalFloat", "SignColumn", "MsgArea",
    "TelescopeNormal", "TelescopeBorder", "StatusLine", "StatusLineNC",
    "BufferLineFill", "BufferLineBackground", "LineNr", "CursorLineNr",
    "FloatBorder",
  }
  for _, grp in ipairs(transparent) do
    vim.api.nvim_set_hl(0, grp, { bg = "none" })
  end

  -- Re‑apply matching bracket highlights after every theme change
  vim.api.nvim_create_autocmd({ "ColorScheme", "User" }, {
    pattern = { "LazyDone", "VeryLazy" },
    callback = function()
      vim.api.nvim_set_hl(0, "MatchParen",    { bg = "#ff33aa", fg = "#000000", bold = true })
      vim.api.nvim_set_hl(0, "MatchParenCur", { bg = "#ff33aa", fg = "#000000", bold = true })
      vim.api.nvim_set_hl(0, "MatchWord",     { bg = "#5555ff", fg = "#000000" })
    end,
  })
end
return M

    

By using raw hex codes, the highlights stay identical whether you run Nordic, Tokyonight, or the fallback Desert. The autocommand on ColorScheme ensures that even if a plugin reloads the theme, your custom highlights survive.

Global Keymaps & User Commands Top

lua/config/keymaps.lua and lua/config/commands.lua form a unified toolbelt. Every keybinding has a corresponding user command, and every command delegates to a single function. This makes the system auditable, remappable, and self‑documenting.

keymaps.lua


local opts = { noremap = true, silent = true }
local functions = require("config.functions")

-- Clipboard
vim.keymap.set("n", "cc", 'gg"+yG', opts)
vim.keymap.set("v", "<C-c>", '"+y', opts)
vim.keymap.set("i", "<C-v>", '<C-r>+', opts)

-- Buffer / window navigation
vim.keymap.set("n", "<Tab>", ":bn<CR>", opts)
vim.keymap.set("n", "<S-Tab>", ":bp<CR>", opts)
vim.keymap.set("n", "<C-h>", "<C-w>h", opts)
vim.keymap.set("n", "<C-j>", "<C-w>j", opts)
vim.keymap.set("n", "<C-k>", "<C-w>k", opts)
vim.keymap.set("n", "<C-l>", "<C-w>l", opts)

-- Automation tools
vim.keymap.set("n", "<leader>wc",    functions.word_count, opts)
vim.keymap.set("n", "<leader>cc",    functions.command_history_explorer, opts)
vim.keymap.set("n", "<leader>rr",    functions.output_regs, opts)
vim.keymap.set("n", "<leader>hh",    functions.wrap_code_in_buffer, opts)
vim.keymap.set("n", "<leader>ranger",functions.ranger_chooser, opts)
vim.keymap.set("n", "<leader>mm",    functions.output_old_files, opts)

-- etc. (see the full file)

    

commands.lua


local functions = require("config.functions")

vim.api.nvim_create_user_command("WC", functions.word_count, {})
vim.api.nvim_create_user_command("Mm", functions.output_old_files, {})
vim.api.nvim_create_user_command("Cc", functions.command_history_explorer, {})
vim.api.nvim_create_user_command("Ss", functions.search_command_history, {})
vim.api.nvim_create_user_command("Rr", functions.output_regs, {})
vim.api.nvim_create_user_command("HH", functions.wrap_code_in_buffer, {})
vim.api.nvim_create_user_command("RangerChooser", functions.ranger_chooser, {})
vim.api.nvim_create_user_command("SaveVimInfo", functions.save_vim_bindings_and_functions, {})
vim.api.nvim_create_user_command("EngType", functions.eng_type, {})
vim.api.nvim_create_user_command("FrType", functions.fr_type, {})

    

Mnemonic prefixes make the system self‑documenting: <leader>wcword count, <leader>cccommand history, etc.

Automation Functions — functions.lua Top

lua/config/functions.lua is the heart of the automation layer. It provides async Python/LaTeX runners, a searchable command history, a register inspector, an “old files” browser, a ranger file‑chooser, buffer‑wrapping utilities, and more. All are written in pure Lua with no plugin dependencies.

Asynchronous Python Execution


function M.run_python_selection()
  local mode = vim.fn.mode()
  if mode ~= 'v' and mode ~= 'V' then return end
  local save_reg = vim.fn.getreg('"')
  vim.cmd('normal! gvy')
  local code = vim.fn.getreg('"')
  vim.fn.setreg('"', save_reg)
  code = "from math import *\n" .. code:gsub('^%s*', ''):gsub('%s*$', '')
  local output = vim.fn.system({'python3', '-c', code})
  vim.cmd('enew')
  vim.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(output, "\n"))
  vim.bo.buftype = 'nofile'
  vim.bo.bufhidden = 'wipe'
end

    

Command History Explorer


function M.command_history_explorer()
  local history = {}
  for i = vim.fn.histnr(':'), 1, -1 do
    local cmd = vim.fn.histget(':', i)
    if cmd ~= "" then table.insert(history, cmd) end
  end
  vim.cmd('enew')
  local buf = vim.api.nvim_get_current_buf()
  vim.api.nvim_buf_set_lines(buf, 0, -1, false, history)
  vim.bo[buf].buftype = 'nofile'
  vim.bo[buf].modifiable = false
  vim.keymap.set('n', '<CR>', function()
    local cmd = vim.fn.getline('.')
    vim.cmd('bd! ' .. buf)
    vim.cmd(cmd)
  end, { buffer = buf })
  vim.cmd('normal! gg')
end

    

Register Inspector


function M.output_regs()
  vim.cmd('enew')
  local content = {}
  for reg = string.byte('a'), string.byte('z') do
    local ch = string.char(reg)
    local val = vim.fn.getreg(ch)
    if val ~= '' then
      table.insert(content, ch .. ":")
      table.insert(content, val)
      table.insert(content, "")
    end
  end
  vim.api.nvim_buf_set_lines(0, 0, -1, false, content)
  vim.bo.buftype = 'nofile'
  vim.bo.bufhidden = 'wipe'
  vim.cmd('normal! gg')
end

    

The file also contains run_python_and_replace, output_old_files, ranger_chooser, wrap_code_in_buffer, word_count, select_inside_any_pair, and several language‑specific helpers. You can find the complete source in the included zip file at the end of the article.

Per‑Filetype Engines — ftplugin Top

Filetype‑specific behaviour lives in ftplugin/. Each file sets buffer‑local options and defines insert‑mode expansions. Visual‑mode wrappers for HTML and Markdown are centralised in a shared module to avoid duplication.

Python ftplugin


-- ftplugin/python.lua
vim.bo.tabstop = 4
vim.bo.shiftwidth = 4
vim.bo.expandtab = true
vim.bo.textwidth = 88

-- Run buffer asynchronously (full function omitted for brevity)
vim.keymap.set('n', '<leader>c', run_python_buffer, { buffer = true })

-- Insert-mode expansions
local imaps = {
  ['if']    = 'if :<++><ESC>F:a',
  ['for']   = 'for in :<++><ESC>F:i',
  ['def']   = 'def ():<++><ESC>F(a',
  ['class'] = 'class :<++><ESC>F:a',
  ['imp']   = 'import ',
  ['from']  = 'from import <++><ESC>F:i',
  -- … many more
}
for lhs, rhs in pairs(imaps) do
  vim.keymap.set('i', lhs, rhs, { buffer = true })
end

    

LaTeX ftplugin


-- ftplugin/tex.lua (excerpt)
vim.bo.tabstop = 2
vim.bo.shiftwidth = 2

-- Async compilation and PDF viewer
vim.keymap.set('n', '<leader>c', run_tex,  { buffer = true })
vim.keymap.set('n', '<leader>o', view_tex, { buffer = true })
vim.keymap.set('n', '<leader>w', wrap_buffer_in_html_tags, { buffer = true })

-- Insert-mode shortcuts for commands, environments, and symbols
local imaps = {
  ['!'] = '\\',
  ['qq'] = '\\quad ',
  [',bf'] = '\\textbf{}<++><ESC>F{a',
  [',u']  = '\\underline{}<++><ESC>F{a',
  -- … dozens more
}
for lhs, rhs in pairs(imaps) do
  vim.keymap.set('i', lhs, rhs, { buffer = true })
end

    

HTML & Markdown ftplugins


-- ftplugin/html.lua
vim.bo.tabstop = 2
vim.bo.shiftwidth = 2
local imaps = {
  ['!'] = '<!--  --><++><Esc>F i',
  ['<'] = '<><++><Esc>F>a',
}
for lhs, rhs in pairs(imaps) do
  vim.keymap.set('i', lhs, rhs, { buffer = true })
end
require("config.html_markdown_maps")()

-- ftplugin/markdown.lua
vim.bo.tabstop = 2
vim.bo.shiftwidth = 2
require("config.html_markdown_maps")()

    

Shared Visual Wrappers — html_markdown_maps.lua

This module registers visual‑mode mappings that work identically in HTML and Markdown buffers. It uses a pure‑Lua wrap_visual_text function that handles linewise, characterwise, and blockwise selections.


-- lua/config/html_markdown_maps.lua (core wrapping function)
local function wrap_visual_text(open_tag, close_tag)
  local mode = vim.fn.visualmode()
  -- … normalises start/end, gets the visual selection,
  -- and wraps it with open_tag .. text .. close_tag
  -- (full implementation in the included zip file at the end of the article)
end

return function()
  vim.keymap.set('v', '<leader>pp', function() wrap_visual_text('<p>', '</p>') end)
  vim.keymap.set('v', '<leader>hh', function() wrap_visual_text('<h2>', '</h2>') end)
  -- … and many more wrapping / escaping shortcuts
end

    

Additionally, the file defines a set of number‑prefixed visual maps (19) for common transformations: escaping symbols, wrapping in code blocks, URL‑encoding, and more. See the included zip file at the end of the article for the full content.

Snippets as Code — LuaSnip Integration Top

Snippets are defined in two files: tex_snippets.lua and html_snippets.lua. They use LuaSnip’s function nodes for dynamic behaviour, read legacy snippet files on demand, and auto‑number LaTeX exercises based on buffer content.

LaTeX Snippets


-- tex_snippets.lua (excerpt)
local ls = require("luasnip")
local s = ls.snippet
local i = ls.insert_node
local t = ls.text_node
local f = ls.function_node

-- Auto‑numbered exercise environment
s("exe", {
  t("\\begin{exe}{"), i(1, "<++>"), t("}"),
  t({"", "    "}), f(function()
    local count = 0
    for _, line in ipairs(vim.api.nvim_buf_get_lines(0, 0, -1, false)) do
      if line:match("\\begin{exe}") then count = count + 1 end
    end
    return tostring(count)
  end),
  t({"", "    <++>", "\\end{exe}"}),
})

    

The file also wraps legacy snippet files from ~/.vim/snippets/latex/ so they appear as native LuaSnip snippets, and exports functions that can be called directly from insert‑mode mappings (e.g., ,tcb in the LaTeX ftplugin).

HTML / Markdown Snippets


-- html_snippets.lua
local snippets = {
  s("fig", {
    t("<figure>"),
    t({ "", "    " }),
    t('<img src="/theme/images/articles/'), i(1, "image.png"),
    t('" alt="'), i(2, "description"), t('" style="max-width:100%;height:auto;" >'),
    t({ "", "    " }),
    t("<figcaption>"), i(3, "caption"), t("</figcaption>"),
    t({ "", "</figure>" }),
    i(0),
  }),
  -- … anchor link, code block with raw tags, etc.
}
ls.add_snippets("html", snippets)
ls.add_snippets("markdown", snippets)

    

The Plugin Dashboard — core.lua Top

lua/plugins/core.lua lists every plugin. Each one lazy‑loads on an event, command, or filetype. The full specification is shown below.


return {
  -- Themes (loaded immediately)
  { "AlexvZyl/nordic.nvim",          lazy = false, priority = 1000 },
  { "folke/tokyonight.nvim",         lazy = false, priority = 1000 },

  -- Telescope (fuzzy finder)
  {
    "nvim-telescope/telescope.nvim",
    dependencies = { "nvim-lua/plenary.nvim" },
    cmd = "Telescope",
    config = function()
      local builtin = require("telescope.builtin")
      vim.keymap.set("n", "<leader>ff", builtin.find_files)
      vim.keymap.set("n", "<leader>fg", builtin.live_grep)
      vim.keymap.set("n", "<leader>fb", builtin.buffers)
      vim.keymap.set("n", "<leader>fh", builtin.help_tags)
    end,
  },

  -- Treesitter (syntax highlighting and indentation)
  {
    "nvim-treesitter/nvim-treesitter",
    build = ":TSUpdate",
    event = { "BufReadPost", "BufNewFile" },
    config = function()
      require("nvim-treesitter.configs").setup({
        ensure_installed = {
          "lua", "python", "javascript", "html", "css", "bash", "c", "cpp", "json", "yaml",
        },
        highlight = { enable = true },
        indent = { enable = true },
      })
    end,
  },

  -- Mason (LSP/DAP/linter manager)
  {
    "williamboman/mason.nvim",
    build = ":MasonUpdate",
    config = function() require("mason").setup() end,
  },

  -- nvim-cmp + LuaSnip (completion & snippets)
  {
    "hrsh7th/nvim-cmp",
    dependencies = {
      "hrsh7th/cmp-nvim-lsp",
      "hrsh7th/cmp-buffer",
      "hrsh7th/cmp-path",
      "saadparwaiz1/cmp_luasnip",
      "L3MON4D3/LuaSnip",
    },
    event = "InsertEnter",
    config = function()
      local cmp = require("cmp")
      local luasnip = require("luasnip")
      vim.o.completeopt = "menu,menuone,noselect"
      cmp.setup({
        snippet = {
          expand = function(args) luasnip.lsp_expand(args.body) end,
        },
        mapping = cmp.mapping.preset.insert({
          ['<C-Space>'] = cmp.mapping.complete(),
          ['<CR>'] = cmp.mapping.confirm({ select = true }),
          ['<Tab>'] = cmp.mapping(function(fallback)
            if cmp.visible() then cmp.select_next_item()
            elseif luasnip.expand_or_jumpable() then luasnip.expand_or_jump()
            else fallback() end
          end, { "i", "s" }),
          ['<S-Tab>'] = cmp.mapping(function(fallback)
            if cmp.visible() then cmp.select_prev_item()
            elseif luasnip.jumpable(-1) then luasnip.jump(-1)
            else fallback() end
          end, { "i", "s" }),
        }),
        sources = cmp.config.sources({
          { name = 'nvim_lsp' },
          { name = 'luasnip' },
          { name = 'buffer' },
          { name = 'path' },
        }),
      })
      -- Load our custom snippets
      require("config.tex_snippets")
      require("config.html_snippets")
    end,
  },

  -- Minimal bufferline
  {
    "akinsho/bufferline.nvim",
    version = "*",
    config = function()
      require("bufferline").setup({
        options = {
          mode = "buffers",
          show_buffer_close_icons = false,
          show_close_icon = false,
          truncate_names = false,
          diagnostics = false,
          separator_style = { "|", "|" },
          always_show_bufferline = true,
          numbers = "none",
        },
      })
    end,
  },
}

    

Equally important is what’s not included: no file‑tree plugin (ranger and Telescope cover navigation), no statusline plugin (the built‑in one plus custom highlights suffice), and no AI‑powered completion. Every plugin must justify its presence.

Putting It All Together Top

When you start Neovim:

  1. init.lua sets options, loads lazy.nvim, and schedules the colour setup.
  2. Lazy.nvim parses plugins/core.lua and begins loading plugins by their lazy‑load triggers.
  3. The scheduled callback applies the theme, defines global keymaps and commands.
  4. When a buffer is opened, Treesitter attaches, the appropriate ftplugin fires, and snippets register for that filetype.
  5. On InsertEnter, nvim‑cmp activates with all snippet and LSP sources ready.

At no point does the user wait for a progress bar. The entire plugin set, once cached, starts in under 100 milliseconds.

Reproducibility & Final Thoughts Top

This configuration is a build artifact. The lazy-lock.json pins every plugin version, the colours are hard‑coded hex values, and every snippet and function is defined in Lua. To replicate the environment on a new machine, you only need:




    # extract the zip file and
    cp nvim ~/.config/nvim
    nvim --headless "+Lazy sync" +qa

After that, your editor will start in under 100 ms and behave exactly as it does today.

The seven companion articles dive deeper into each subsystem: the bootstrapping layer, filetype engines, custom functions, snippets, colours, keymaps/commands, and the plugin ecosystem. But the article you’ve just read contains the complete source and the reasoning you need to build your own ultimate Neovim setup.


← Engineering Deterministic Prompts for LLM Agents: A Systems Design Approach Replaying CSS Builds: A Recipe-Based Manager for Pelican Themes →

Leave a comment