- Neovim: 0.10.0 or higher
- Package Manager: At least one of the following installed:
- npm (Node.js)
- yarn
- pnpm
- Composer (PHP)
- Optional: Docker (for containerized package management)
Imagine this: you’re in Neovim, and you want to keep an eye on your installed, outdated, abandoned packages, or you wanna quickly update, remove or add them without having to leave the editor in a single keystroke. Well, now you can! With this plugin, you can toggle package versions right inside your main package manager file.
Install plugin using package manager of your choice, for example with
{
"nemanjajojic/package-version.nvim",
version = "*", -- Use latest stable semver release or with specific constraints eg. version = "^0.6.8"
dependencies = { "folke/which-key.nvim" }, --- this is an optional dependency
config = function()
require("package-version").setup()
end
}You have the following commands available:
:PackageVersionInstalled- toggle installed package version:PackageVersionOutdated- toggle outdated package version:PackageVersionHomepage- open package homepage or repository in browser
Note
PackageVersionHomepage command will try to open the homepage URL for the package under cursor. If homepage is not available, it falls back to the repository URL (if browser-friendly).
:PackageVersionUpdateAll- update all outdated packages:PackageVersionUpdateSingle- update single package under cursor
Note
Composer users: When running update commands, you'll be prompted to choose an update scope:
- Latest - Updates to the latest version within semver constraints (default behavior)
- Patch - Only allows patch version updates (e.g., 2.9.1 → 2.9.3, but not 2.9.1 → 2.10.0)
This feature uses Composer's --patch-only flag and is only available for Composer. Other package managers (npm, yarn, pnpm) will update directly without prompting.
:PackageVersionInstall- install packages from lock file:PackageVersionRemove- remove package under cursor from dependencies:PackageVersionAddNew- add a new package (prompts for dependency type and package name):PackageVersionAudit- check if any installed packages has known vulnerabilities
Note
PackageVersionRemove command:
- Removes the package under cursor from your dependencies
- Composer only: Prompts to select dependency type (Production or Development) before removal
- npm/yarn/pnpm: Automatically detects and removes from the correct section (no prompt needed)
- If removal fails (e.g., due to dependency conflicts), an error window will display the detailed error message
PackageVersionAddNew command uses a two-step flow:
- Select dependency type - Choose between Production or Development dependencies
- Enter package name - Specify which package to install
PackageVersionInstall command
If installation fails, an error window displays the detailed error message.
:PackageVersionClearCache- clear all cached package data:PackageVersionCacheStats- show cache statistics (list of cache keys with expiration status)
For more visual examples of commands in action, go check COMMANDS.md
If you already using which-key, you can use default keybinding
provided by plugin.
<leader>vi- toggle installed package version<leader>vo- toggle outdated package version<leader>vh- open package homepage/repository in browser<leader>vu- update all outdated packages according to semver range<leader>vs- update single package according to semver range<leader>vI- install packages from lock file<leader>vr- remove package under cursor<leader>va- add a new package<leader>vA- audit
<leader>vcc- clear all cached package data<leader>vcs- show cache statistics
Important
If you are not using which-key, you can set keybindings to your preference eg.
{
"nemanjajojic/package-version.nvim",
cmd = { "PackageVersionInstalled" },
config = function()
require("package-version").setup()
end,
keys = {
-- Here you can set your preferred keybinding eg.
{
"<leader>key",
"<cmd>PackageVersionInstalled<cr>",
mode = "n",
desc = "Toggle installed package version"
},
}
}
You don’t have to change anything, but if you want to, you can customize it to your liking.
[NOTE] Plugin will override only properties you set
config = function()
require("package-version").setup({
color = {
latest = "",
wanted = "",
current = "",
abandoned = "",
},
spinner = {
type = "pacman" | "ball" | "space" | "minimal" | "dino"
},
-- Command timeout in seconds (default: 60, max: 300)
timeout = 60
cache = {
-- Enable caching (default: true)
enabled = true
ttl = {
-- Cache duration for installed packages in seconds (default: 300 / 5 minutes)
installed = 300,
-- Cache duration for outdated packages in seconds (default: 300 / 5 minutes)
outdated = 300,
},
warmup = {
-- Debounce warmup triggers in milliseconds (default: 500)
debounce_ms = 500,
ttl = {
-- Warmup cache duration for installed packages (default: 3600 / 1 hour)
-- Set to 0 to disable warmup for installed packages
installed = 3600,
-- Warmup cache duration for outdated packages (default: 3600 / 1 hour)
-- Set to 0 to disable warmup for outdated packages
outdated = 3600,
},
-- Enable warmup on code files (*.js, *.ts, *.php, etc.)
-- Default: false (only triggers on package files)
enable_code_files = false,
}
},
docker = {
composer_container_name = "your_composer_container_name",
npm_container_name = "your_npm_container_name",
yarn_container_name = "your_yarn_container_name",
pnpm_container_name = "your_pnpm_container_name",
}
})
end
In order to align plugin with color scheme of your choice, you should should customize this config according to your preferences.
Note
You can use hexadecimal color codes (e.g., #FF5733)
or Neovim highlight group names (e.g., Comment, String, Error).
Using Neovim highlight group names will be more adaptive to changing themes
Examples:
color = {
latest = "#a6e3a1", -- Hex color (catppuccin green)
wanted = "#f9e2af", -- Hex color (catppuccin yellow)
current = "Comment", -- Neovim highlight group
abandoned = "ErrorMsg", -- Neovim highlight group
}latest- latest version availablewanted- latest available version that matches semver rangecurrent- currently installed versionabandoned- abandoned or deprecated package
Some of command can take more time to execute, so spinner is added to provide better user experience, while background task is running.
Note
space is default spinner type.
You have couple of options to choose from. Please check SPINNERS.md
All commands (installed, outdated, update) have a built-in timeout protection to prevent hung operations.
- Default: 60 seconds
- Range: 1 - 300 seconds (5 minutes max)
- Behavior: If a command exceeds the timeout, it will be automatically stopped and an error message will be shown
Example:
require("package-version").setup({
timeout = 60,
})Note
If you have a lot of private packages or slow network connections, you may want to increase the timeout value.
The plugin includes caching system to improve performance and reduce unnecessary package manager calls.
- Default: Enabled with 5 minute TTL
- TTL Range: 0 - 3600 seconds (1 hour max)
Example:
require("package-version").setup({
cache = {
enabled = true, -- Enable/disable caching system
ttl = {
installed = 300, -- Cache installed packages for 5 minutes
outdated = 300, -- Cache outdated packages for 5 minutes
}
}
})Tip
- Set
ttl = 0to disable caching for specific operations
Note
If you frequently update packages outside of Neovim, you may want to reduce the TTL value or disable caching to ensure fresh data.
The plugin includes an automatic cache warmup feature that pre-populates the cache when you open package files. This provides instant results when you run commands, without the wait!
Warmup Triggers (by default):
- Package manifests:
package.json,composer.json - Lock files:
package-lock.json,yarn.lock,pnpm-lock.yaml,composer.lock
Optional: Warmup on Code Files
You can enable warmup triggers on code files (.js, .jsx, .ts, .tsx, .mjs, .cjs, .php)
by setting cache.warmup.enable_code_files = true. This is opt-in because it's more
aggressive and may not be needed for all workflows.
Note
When enable_code_files = true, the debounce time is automatically increased to a minimum of
5 seconds (regardless of debounce_ms setting) to prevent excessive warmup triggers when
rapidly switching between code files.
Tip
Warmup respects the main cache.enabled flag. If caching is disabled, warmup will not run.
To disable only warmup (keeping manual cache), set the warmup TTL values to 0.
Example
require("package-version").setup({
cache = {
warmup = {
debounce_ms = 500, -- Wait time before triggering warmup (default: 500)
-- Note: Automatically increased to 5000ms when enable_code_files = true
ttl = {
installed = 3600, -- Warmup cache duration (default: 3600 / 1 hour), set to 0 to disable
outdated = 3600, -- Warmup cache duration (default: 3600 / 1 hour), set to 0 to disable
},
enable_code_files = false, -- Enable warmup on *.js, *.ts, *.php, etc. (default: false)
}
}
})Warmup TTL Settings:
- Range: 0 - 86400 seconds (24 hours max)
- Default: 3600 seconds (1 hour)
- Set to 0 to disable warmup
Tip
The warmup TTL is separate from manual command TTL. User commands always fetch fresh data (5 min cache), while warmup uses a longer cache (1 hour) to minimize API calls.
Plugin support both local and docker environment. You have full control to decide which one you wanna use.
In case you are using docker environment, you have to set proper container name for each package manager.
composer_container_name- in case you wanna use composernpm_container_name- in case you wanna use npmyarn_container_name- in case you wanna use yarnpnpm_container_name- in case you wanna use pnpm
In case you wanna use local installation of package manager,
docker should not be set inside of a config.
Important
All package managers must be installed and available in your system PATH.
Run :checkhealth package-version command to check if plugin is properly
configured and have everything need to work properly.
The health check validates:
- Configuration - Verifies your setup configuration is valid
- Package Manager Availability - Ensures required package managers or Docker are available
Docker Mode:
- If you configure
dockeroption, Docker must be installed on your system - At least one container must be configured
- ❌ ERROR if docker config is set but docker is not installed
Local Mode:
- If no
dockeroption is configured, at least one package manager must be in your PATH - ❌ ERROR if no docker config AND no local package managers are found
- ✅ OK if at least one package manager (composer, npm, pnpm, or yarn) is available
- Nerd Fonts - for providing awesome icons
- jellydn - for providing base spinner functionality
- ileriayo - for providing markdown badges
Go checkout TODO.md
If you find this plugin helpful, please consider giving it a star
