This document details all available options when defining plugin specifications.
{ 'user/repo' } -- Expands to https://github.com/user/repo
{ src = 'https://github.com/user/repo' }
{ src = '/path/to/local/plugin' }
| Field | Type | Description |
|---|
[1] | string | Short name (user/repo) |
src | string | Source URL or local path |
dir | string | Local directory (lazy.nvim compat) |
url | string | Git URL (lazy.nvim compat) |
name | string | Custom plugin name |
| Field | Type | Description |
|---|
version | string|boolean | Branch, tag, commit, or semver wildcard |
version | Range | Semver range via vim.version.range() |
sem_version | string | Semver (lazy.nvim compat) |
branch | string | Git branch |
tag | string | Git tag |
commit | string | Git commit hash |
{ 'user/repo', version = 'main' } -- Branch
{ 'user/repo', version = 'v1.0.0' } -- Tag
{ 'user/repo', version = '1.*' } -- Semver wildcard
{ 'user/repo', version = '^1.0.0' } -- Semver range
{ 'user/repo', version = 'abc123' } -- Commit
{ 'user/repo', version = false } -- Disable semver (track default)
{ 'user/repo', version = vim.version.range('^1.0') } -- Explicit Range object
| Field | Type | Description |
|---|
dependencies | string|string[]|Spec|table | Plugin dependencies |
optional | boolean | Optional dependency flag |
-- Simple string
{ 'user/repo', dependencies = 'dep/plugin' }
-- String array
{ 'user/repo', dependencies = { 'dep1', 'dep2' } }
-- lazy.nvim multi-string format
{ 'user/repo', dependencies = { 'dep1', { 'dep2', 'dep3' } } }
-- Full specs
{ 'user/repo', dependencies = {
{ 'dep/plugin', opts = {} },
} }
-- Optional dependency
{ 'user/repo', dependencies = {
{ 'optional/dep', optional = true },
} }
| Field | Type | Description |
|---|
enabled | boolean|function | Enable/disable plugin |
cond | boolean|function | Conditional loading |
lazy | boolean | Force lazy loading |
priority | number | Load priority (higher = earlier) |
-- Enable based on condition
{ 'user/repo', enabled = vim.fn.has('linux') == 1 }
-- Conditional loading
{ 'user/repo', cond = function()
return vim.fn.filereadable('.project') == 1
end }
-- Force eager loading
{ 'user/repo', lazy = false }
-- Load priority (higher loads first)
{ 'user/repo', priority = 100 }
| Field | Type | Description |
|---|
dev | boolean | Enable dev mode |
dir | string | Local plugin path |
{ 'user/repo', dev = true, dir = '~/projects/plugin-name' }
| Field | Type | Description |
|---|
event | string|string[]|table | Neovim events |
{ 'user/repo', event = 'InsertEnter' }
{ 'user/repo', event = { 'InsertEnter', 'CmdlineEnter' } }
{ 'user/repo', event = 'BufReadPre *.lua' }
{ 'user/repo', event = 'VeryLazy' } -- After UIEnter
For event, you can specify a fallback pattern:
| Field | Type | Description |
|---|
pattern | string | Fallback autocmd pattern (default: *) |
{ 'user/repo', event = 'BufReadPre', pattern = '*.lua' }
| Field | Type | Description |
|---|
cmd | string|string[] | User commands |
{ 'user/repo', cmd = 'MyCommand' }
{ 'user/repo', cmd = { 'Cmd1', 'Cmd2' } }
| Field | Type | Description |
|---|
keys | string|table|table[] | Keymaps |
-- Simple key
{ 'user/repo', keys = '<leader>f' }
-- With options
{ 'user/repo', keys = {
{ '<leader>f', function() require('plugin').action() end, desc = 'Action' },
{ '<leader>g', '<cmd>PluginCmd<cr>', mode = 'n', desc = 'Command' },
} }
| Field | Type | Description |
|---|
ft | string|string[] | File types |
{ 'user/repo', ft = 'lua' }
{ 'user/repo', ft = { 'lua', 'vim' } }
| Field | Type | Description |
|---|
init | function | Runs before plugin loads |
config | function|boolean | Runs after plugin loads |
build | string|function | Runs on install/update |
opts | table | Auto-setup options |
-- Init hook (runs before load)
{ 'user/repo', init = function()
vim.g.some_setting = true
end }
-- Config function
{ 'user/repo', config = function()
require('plugin').setup({ option = 'value' })
end }
-- Auto-setup with opts
{ 'user/repo', opts = { option = 'value' } }
-- Build hook (string)
{ 'user/repo', build = 'make' }
-- Build hook (function)
{ 'user/repo', build = function()
vim.fn.system({ 'make', '-C', plugin.path })
end }
| Field | Type | Description |
|---|
name | string | Custom plugin name |
main | string | Explicit main module (auto-detected if omitted) |
{ 'user/repo', name = 'my-plugin' }
{ 'user/repo', main = 'plugin.main' } -- Explicit main module
When using opts or config = true without specifying a main field, leanpack will automatically detect the main module. The explicit or auto-detected main module is also used to trigger require()-based lazy loading automatically! The detection process determines the module by:
- Scanning the plugin's
lua/ directory for module folders
- Matching the plugin name against folder names (using normalization like lazy.nvim)
- Looking for
init.lua files in matched folders
Example: For nvimtools/none-ls.nvim, leanpack auto-detects null-ls as the main module (since the internal folder is named null-ls), allowing you to use:
{
'nvimtools/none-ls.nvim',
opts = { sources = {} } -- No main field needed!
}
This matches lazy.nvim's behavior where plugins work out of the box without manual configuration.
return {
'nvim-telescope/telescope.nvim',
cmd = 'Telescope',
dependencies = {
'nvim-lua/plenary.nvim',
{ 'nvim-tree/nvim-web-devicons', opts = {} },
},
opts = {
defaults = {
prompt_prefix = ' ',
},
},
config = function()
local telescope = require('telescope')
telescope.setup(vim.tbl_deep_extend('force', telescope.loaded().telescope.opts, {
defaults = {
mappings = {
n = { ['<c-t>'] = require('telescope._actions').select_tab },
},
},
}))
end,
}