Lazy Loading Strategies in Lazy.nvim: A Complete Guide from jdhao/nvim-config

Lazy.nvim supports eight distinct lazy loading strategies—including event-based, command-based, filetype-based, keymap-based, and conditional triggers—that defer plugin initialization until specific runtime conditions are met, significantly improving Neovim startup performance.

Lazy.nvim has become the de facto plugin manager for Neovim by offering precise control over when plugins are sourced. The jdhao/nvim-config repository demonstrates production-grade implementations of these strategies in lua/plugin_specs.lua, where each plugin is configured with specific triggers to minimize startup overhead while maintaining full editor functionality.

Explicit Lazy Loading with the lazy Flag

The most fundamental strategy uses the lazy boolean to declare whether a plugin should load immediately or defer. When set to true, the plugin waits for other triggers; when false, it loads eagerly at startup.

In lua/plugin_specs.lua at lines 25‑26, the configuration explicitly marks completion sources as lazy:

{"hrsh7th/cmp-nvim-lsp", lazy = true}

This flag works in conjunction with other triggers. A plugin with lazy = true and no additional specifiers will still load eventually, but combining it with events, commands, or keymaps provides deterministic control over initialization timing.

Event-Based Lazy Loading

Event-based loading triggers plugin initialization when specific Neovim autocommand events fire. This strategy is ideal for plugins that only need to function during particular editing phases.

The jdhao/nvim-config repository uses event = "VeryLazy" for the completion engine at lines 34‑38 of lua/plugin_specs.lua:

{
  "hrsh7th/nvim-cmp",
  event = "VeryLazy",
  -- additional configuration
}

Other common events include BufRead (triggered when reading a file), InsertEnter (when entering insert mode), and User InGitRepo for git-specific tools. This approach ensures plugins like status lines or completion engines only load when the user actually begins editing, rather than during initial startup.

Command-Based Lazy Loading

Command-based loading defers plugins until a specific Ex command is executed for the first time. This strategy suits tools invoked explicitly, such as fuzzy finders or git interfaces.

At lines 15‑17 in lua/plugin_specs.lua, Telescope is configured to load only when the :Telescope command is called:

{
  "nvim-telescope/telescope.nvim",
  cmd = "Telescope",
  -- dependencies and configuration
}

When the user types :Telescope find_files, Lazy.nvim automatically sources the plugin and its dependencies before executing the command. This prevents the fuzzy finder from consuming startup resources when not in use.

Filetype-Based Lazy Loading

Filetype-based loading restricts plugins to buffers of specific languages or formats. This is essential for language servers, syntax highlighting, and filetype-specific utilities.

The configuration at lines 31‑33 demonstrates this with a Markdown rendering plugin:

{
  "MeanderingProgrammer/render-markdown.nvim",
  ft = { "markdown" },
  main = "render-markdown",
  opts = {}
}

When opening a .md file, Neovim detects the markdown filetype and triggers Lazy.nvim to load the plugin. This keeps filetype-specific code dormant until actually needed, reducing memory footprint for projects using diverse languages.

Keymap-Based Lazy Loading

Keymap-based loading activates plugins when specific keystrokes are pressed. This strategy works well for navigation tools and text objects that users invoke manually.

At lines 98‑102 of lua/plugin_specs.lua, the Hop motion plugin loads on the f keypress:

{
  "smoka7/hop.nvim",
  keys = { "f" },
  config = function()
    require("config.nvim_hop")
  end
}

The plugin remains unloaded until the user attempts to use the f motion, at which point Lazy.nvim sources the plugin and executes the configuration function before processing the keystroke.

Conditional Loading with cond

Conditional loading uses a Lua function to determine whether a plugin should load at all. This enables environment-specific configurations, such as disabling GUI-heavy plugins in terminal-only sessions.

Lines 74‑78 of lua/plugin_specs.lua show Lualine configured to load only when not running inside Firenvim:

local firenvim_not_active = function() return not vim.g.started_by_firenvim end

{
  "nvim-lualine/lualine.nvim",
  event = "BufRead",
  cond = firenvim_not_active,
  config = function()
    require("config.lualine")
  end
}

The cond function executes during the loading phase; returning false prevents the plugin from loading entirely, while true allows normal lazy loading to proceed.

Dependency and Priority Management

While not loading triggers per se, dependencies and priority influence how and when plugins initialize. Dependencies are installed before the parent plugin and can have their own lazy loading rules.

Lines 40‑52 of lua/plugin_specs.lua demonstrate dependency chains (commented in the source but illustrative):

{
  "blink.cmp",
  dependencies = {
    "rafamadriz/friendly-snippets",
    -- additional dependencies
  }
}

The priority field controls load order when multiple plugins share the same trigger. At lines 51‑52, the Modus theme receives high priority to ensure it loads before other UI plugins:

{"miikanissi/modus-themes.nvim", priority = 1000}

Higher numerical values load earlier, ensuring color schemes initialize before status lines or tab bars that depend on color definitions.

Module-Based and Development Loading

Lazy.nvim supports module loading for plugins that should activate when a Lua module is require‑d, though jdhao/nvim-config does not currently utilize this strategy. However, the repository does demonstrate LazyDev loading at lines 105‑111:

{
  "folke/lazydev.nvim",
  ft = "lua",
  opts = {
    library = { "lazy.nvim" }
  }
}

This provides type annotations and library definitions during Lua development without loading at runtime, using the same lazy mechanism but for development tooling rather than editor features.

Configuration Architecture

The lazy loading strategies are centralized in lua/plugin_specs.lua, which exports a table of plugin specifications. The init.lua file bootstraps Lazy.nvim and calls require("lazy").setup({ spec = plugin_specs }), while lua/utils.lua provides helper functions like firenvim_not_active for conditional checks.

This architecture separates plugin declarations from implementation logic, allowing each plugin's loading strategy to be adjusted independently without modifying core initialization code.

Summary

  • Explicit lazy flag controls default loading behavior (true for deferred, false for eager)
  • Event-based loading triggers on Neovim autocommands like VeryLazy, BufRead, or InsertEnter
  • Command-based loading activates when specific Ex commands (:Telescope) are executed
  • Filetype-based loading restricts plugins to specific buffer types (ft = { "markdown" })
  • Keymap-based loading defers until specific keystrokes are pressed (keys = { "f" })
  • Conditional loading uses Lua functions (cond) to skip plugins based on runtime conditions
  • Dependencies and priority manage load order and ensure prerequisite plugins are available
  • Development loading provides type information without runtime overhead

Frequently Asked Questions

What is the difference between lazy = true and event = "VeryLazy"?

Setting lazy = true marks a plugin for deferred loading but requires an additional trigger to determine exactly when it loads, while event = "VeryLazy" specifically schedules the plugin to load after Neovim finishes startup and enters the main loop. According to the jdhao/nvim-config implementation, VeryLazy is the preferred event for UI components that should appear immediately after startup without blocking the initial render.

How do I lazy load a plugin only for specific filetypes?

Use the ft key with a string or table of filetypes in your plugin specification. As shown in lua/plugin_specs.lua lines 31‑33, the render-markdown plugin uses ft = { "markdown" } to ensure it only loads when editing Markdown files, keeping it dormant during other editing sessions.

Can I combine multiple lazy loading triggers for a single plugin?

Yes, Lazy.nvim allows combining triggers such as event, keys, and cmd on the same plugin specification. The plugin loads when any of its specified conditions are met first. However, in jdhao/nvim-config, most plugins use a single primary trigger to keep the loading logic predictable and debuggable.

Where does jdhao/nvim-config define its lazy loading rules?

All lazy loading specifications are centralized in lua/plugin_specs.lua, with each plugin entry specifying its loading strategy through keys like lazy, event, cmd, ft, keys, or cond. The init.lua file bootstraps the Lazy.nvim manager and passes this specification table to require("lazy").setup(), while helper functions for conditional logic reside in lua/utils.lua.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →