Plugin Patterns and Best Practices
As your plugin list grows, maintaining a clean and efficient configuration becomes critical. This lesson covers organizational patterns, version pinning, and troubleshooting.
Organizing Plugin Files
Each file in lua/plugins/ returns a table (or a list of tables). lazy.nvim loads all of them automatically:
lua/plugins/editor.lua
return {
-- All editor-enhancement plugins in one file
{ "windwp/nvim-autopairs", event = "InsertEnter", opts = {} },
{ "numToStr/Comment.nvim", keys = { "gc", "gcc" }, opts = {} },
{ "kylechui/nvim-surround", version = "*", event = "VeryLazy", opts = {} },
{ "folke/todo-comments.nvim", event = "BufReadPost", opts = {} },
}
Plugin Version Pinning
{
"nvim-telescope/telescope.nvim",
tag = "0.1.8", -- pin to a specific tag
-- or:
version = "^0.1.0", -- semver range
-- or:
commit = "a0bbec2", -- exact commit
}
tip
For production setups, pin at least your most critical plugins (LSP, Telescope, treesitter) to avoid surprise breakage from upstream changes.
Common Essential Plugins
Editor Enhancements
lua/plugins/editor.lua
return {
-- Auto-close brackets
{
"windwp/nvim-autopairs",
event = "InsertEnter",
opts = { check_ts = true },
},
-- Comments
{
"numToStr/Comment.nvim",
keys = {
{ "gcc", mode = "n", desc = "Comment line" },
{ "gc", mode = "v", desc = "Comment selection" },
},
opts = {},
},
-- Surround motions (cs, ds, ys)
{
"kylechui/nvim-surround",
version = "*",
event = "VeryLazy",
opts = {},
},
-- TODO/FIXME/HACK highlighter
{
"folke/todo-comments.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
event = { "BufReadPost", "BufNewFile" },
opts = {},
keys = {
{ "<leader>ft", "<cmd>TodoTelescope<cr>", desc = "Find TODOs" },
},
},
-- Multi-cursor with flash (better than classic vim-multiple-cursors)
{
"folke/flash.nvim",
event = "VeryLazy",
keys = {
{ "s", mode = { "n", "x", "o" }, function() require("flash").jump() end },
{ "S", mode = { "n", "x", "o" }, function() require("flash").treesitter() end },
},
},
-- Better f/t motions
{
"smoka7/hop.nvim",
version = "*",
cmd = { "HopWord", "HopLine" },
opts = { keys = "etovxqpdygfblzhckisuran" },
},
}
UI Plugins
lua/plugins/ui.lua
return {
-- Icons (required by many plugins)
{ "nvim-tree/nvim-web-devicons", lazy = true },
-- Mini icons alternative
-- { "echasnovski/mini.icons", version = false, lazy = true },
-- Improved vim.ui
{
"stevearc/dressing.nvim",
lazy = true,
opts = {},
},
-- Smooth scrolling
{
"karb94/neoscroll.nvim",
event = "WinScrolled",
opts = { mappings = { "<C-u>", "<C-d>", "<C-b>", "<C-f>", "zt", "zz", "zb" } },
},
}
Conditional Plugin Configuration
{
"plugin/name",
-- Only load on specific filetypes
ft = { "javascript", "typescript" },
-- Only if a command is run
cmd = { "SomeCommand" },
-- Only if a key is pressed
keys = { "<leader>ff" },
-- Only load on specific OS
cond = function()
return vim.fn.has("mac") == 1
end,
-- Disable entirely
enabled = false,
}
Debugging Plugin Issues
-- Check if a plugin is loaded
print(require("lazy").plugins()["plugin-name"])
-- Force reload a plugin spec
:Lazy reload plugin-name
-- Startup time analysis
:Lazy profile
-- See plugin logs
:Lazy log plugin-name
Installing Optional Plugin Dependencies
# For Telescope with fzf (faster search)
sudo apt install -y fdfind ripgrep
# For LSP servers
npm install -g typescript-language-server
pip install pyright
# For tree-sitter parsers (some need compilers)
sudo apt install -y gcc g++ make