A lightweight Vim plugin manager that uses Git submodules and Vim 8's native package system.
Platform: Linux only (Debian, Ubuntu, Arch, Gentoo, RHEL family). Windows and macOS are not supported.
Editor: Vim 8.2+ (with
+joband+channel). Neovim already has mature, Lua-based managers (lazy.nvim, packer.nvim) as well as vim-plug, so it is not supported here.
- Manage plugins through Git submodules
- Easy installation, removal, and updating of plugins
- Declarative block (
PluginBegin/Plugin/PluginEnd) with automatic background parallel install of missing plugins - Version pinning:
branch,tagandcommitoptions, with the declared pin re-asserted on every update (the vimrc is the source of truth) - On-demand (lazy) loading:
oncommand triggers andforfiletype triggers - Orphan cleanup:
:PluginManager gccollects submodules no longer declared - Automatic generation of helptags
- Backup your entire Vim configuration to multiple remote repositories
- Works with Vim 8's native package loading system
- Full Git integration for plugin versioning
- Support for optional (lazy-loaded) plugins
- Interactive sidebar interface
- Modern, non-blocking UI with spinners (operations never freeze the editor)
- Asynchronous operations for better performance
- Vim 8.2+ (with
+joband+channel; falls back to synchronous execution otherwise) - Git 2.39+
- Linux (Debian, Ubuntu, Arch, Gentoo, RHEL/AlmaLinux/Rocky); Windows and macOS are not supported
The minimum Vim version is 8.2 and will not be raised without a concrete reason. The floor is set by RHEL 9 and its binary-compatible clones (AlmaLinux 9, Rocky Linux 9), which ship Vim 8.2.2637. RHEL 9 is supported by Red Hat until 2032 and is the dominant enterprise release in the project's target environment.
Vim versions shipped by the targeted distributions:
| Distribution | Vim version |
|---|---|
| RHEL 9 / AlmaLinux 9 / Rocky 9 | 8.2.2637 (the floor) |
| AlmaLinux 10 (RHEL 10 proxy) | 9.1.083 |
| Debian 12 Bookworm | 9.0.1378 |
| Debian 13 Trixie | 9.1.1230 |
| Ubuntu 24.04 LTS | 9.1.0016 |
| Ubuntu 26.04 LTS | 9.1.2141 |
| Arch Linux (rolling) | 9.2.0735 (the ceiling) |
The codebase uses only legacy VimScript and no Vim 9.0+ features. A
vim9script migration is explicitly deferred: the dominant cost of this plugin
is git and network I/O, not script execution, so the rewrite would have no
measurable benefit (YAGNI). The if v:version < 802 guard in
plugin/plugin_manager.vim is therefore correct and intentional.
- Vim 8.2+
- Git 2.39 or higher
- Initialize your Vim configuration as a Git repository (if not already done):
# If you don't already have a Git repository for your Vim configuration
cd ~/.vim
git init- Add the plugin manager as a submodule:
# Add the plugin as a submodule directly to the appropriate location
git submodule add https://github.com/log0u7/vim-plugin-manager.git ~/.vim/pack/plugins/start/vim-plugin-manager- Generate helptags (choose one method):
# From the command line
vim -c "helptags ~/.vim/pack/plugins/start/vim-plugin-manager/doc" -c qOr after opening Vim:
:helptags ~/.vim/pack/plugins/start/vim-plugin-manager/docThat's it! The plugin manager will automatically create necessary directories when you install plugins.
Since the plugin manager uses Git to manage your .vim directory, it can create and version control various subdirectories (like .vim/plugin, .vim/ftdetect, .vim/ftplugin, etc.) for its own configurations and mappings.
A good practice is to create your own configuration files for each plugin you install. For example:
~/.vim/plugin/nerdtree_config.vim
~/.vim/plugin/fzf_config.vim
~/.vim/plugin/fugitive_config.vim
A complete real-world implementation of this practice is
MyVim: one file per plugin, with a
vim_* / plugin_* naming convention separating pure-Vim settings from
per-plugin configuration, plus ftplugin/ and doc/ shipped inside the
plugin. See its README and :help myvim.
These files will be automatically included in backups when using :PluginManager backup since the plugin manager will commit all changes in your Vim configuration directory before pushing to remote repositories. This ensures that all your custom configurations, mappings, and settings are properly versioned and backed up.
Real extracts from the MyVim repository
(plugin/ directory):
NERDTree Configuration (plugin/plugin_nerdtree.vim):
" Plugin NERDTree
let NERDTreeShowBookmarks = 1 " Show the bookmarks table
let NERDTreeShowHidden = 1 " Show hidden files
let NERDTreeWinPos = 'left' " Panel opens on the left side
let NERDTreeIgnore=['\.git$','.swp$'] " Ignore some files and directories
" (the <F2> toggle is centralized in plugin/vim_mappings.vim)FZF mappings (plugin/vim_mappings.vim, shared by all completion tools):
" fzf (ctrlp keeps <C-p> via its own default mapping)
nnoremap <leader>p :Files<CR>
nnoremap <leader>b :Buffers<CR>
nnoremap <leader>g :GFiles<CR>Secrets never committed (plugin/plugin_fugitive.vim + gitignored file):
" in plugin/plugin_fugitive.vim: tokens live in a gitignored file,
" see "Secrets" in the MyVim README and the plugin/*-secrets.vim patternTo exclude certain files from version control, create a .gitignore file in your Vim configuration directory:
# Create a .gitignore file
touch ~/.vim/.gitignoreAdd the following content to exclude temporary files, undo history, swap files, and helptags:
# Ignore undo history
undodir/*
# Ignore swap files
*.swp
*.swo
.*.swp
.*.swo
swapdir/*
# Ignore helptags
doc/tags
**/doc/tags
# Ignore netrw history
.netrwhist
# Ignore session files
session/*
# Ignore local vimrc files
.exrc
.vimrc.local
Make sure to commit your .gitignore file:
git add .gitignore
git commit -m "Add .gitignore for Vim configuration"If you prefer, you can create your own plugin structure as a Git submodule:
# Create your custom Vim configuration repository
mkdir ~/my-vim-config
cd ~/my-vim-config
git init
# Create the standard Vim directory structure
mkdir -p plugin ftplugin ftdetect syntax autoload doc colors after
# Add your configurations to the appropriate directories
# For example:
touch plugin/mappings.vim
touch plugin/settings.vim
touch plugin/plugin_configs.vim
# Commit your changes
git add .
git commit -m "Initial setup of my Vim configuration"
# Push to your own repository (optional)
git remote add origin https://github.com/yourusername/my-vim-config.git
git push -u origin main
# Now add this as a submodule to your Vim configuration
# You can use either direct Git command:
cd ~/.vim
git submodule add https://github.com/yourusername/my-vim-config.git pack/personal/start/my-vim-config
# Or use PluginManager itself:
:PluginManager add https://github.com/yourusername/my-vim-config.git {'dir':'my-vim-config'}This approach keeps your personal configurations organized and separate from the plugin manager and other plugins.
" Install a plugin from GitHub (username/repo format)
:PluginManager add tpope/vim-fugitive
" Install a plugin to start/ directory (auto-loaded) using full URL
:PluginManager add https://github.com/tpope/vim-fugitive.git
" Install with options (new format)
:PluginManager add tpope/vim-surround {'dir':'surround', 'load':'start', 'branch':'main'}
" Install as an optional plugin with a specific tag
:PluginManager add tpope/vim-commentary {'load':'opt', 'tag':'v1.3'}
" Install a plugin and run a command after installation
:PluginManager add junegunn/fzf {'exec':'./install --all'}
" For backward compatibility:
" Install with a custom name (old format)
:PluginManager add tpope/vim-surround surround
" Install as an optional plugin (old format)
:PluginManager add tpope/vim-commentary commentary opt
" Install a plugin from a custom URL (non-GitHub)
:PluginManager add https://gitlab.com/user/repo.git
" Install pinned to an exact commit (detached HEAD, re-asserted on update)
:PluginManager add tpope/vim-commentary {'commit': 'c0e2fbd'}
" Install from a local bare repository (file:// remote, handy for testing)
:PluginManager add file:///srv/git/vim-fugitive.gitYou can define all your plugins in your vimrc file using the declarative syntax. This is especially helpful for managing multiple plugins and ensuring your setup is reproducible:
" In your vimrc file:
PluginBegin
" Basic syntax: Plugin 'username/repo'
Plugin 'tpope/vim-fugitive'
Plugin 'tpope/vim-surround'
" With options:
Plugin 'preservim/nerdtree', {'on': ['NERDTreeToggle']}
Plugin 'vimwiki/vimwiki', {'for': ['markdown']}
Plugin 'junegunn/fzf', {'dir': 'fzf', 'exec': './install --all'}
Plugin 'fatih/vim-go', {'tag': 'v1.28'}
Plugin 'neoclide/coc.nvim', {'branch': 'release'}
Plugin 'tpope/vim-commentary', {'commit': 'c0e2fbd'}
" Local plugin (from filesystem):
Plugin '~/projects/my-vim-plugin'
PluginEndWhen Vim loads your vimrc, all these plugins will be installed automatically if they don't exist yet: clones run in parallel in the background through the async queue (sequential fallback without +job/+channel), and each completed clone is registered as a submodule with its pointer committed. This allows you to easily manage your plugin collection and share your configuration with others.
MyVim is a live configuration plugin
managed with this manager: every plugin is declared in the PluginBegin
block of ~/.vim/vimrc (one Git submodule per plugin under
pack/plugins/start/), and MyVim itself is declared last, shipping the
per-plugin settings and mappings as plugin/vim_*.vim (pure Vim config)
and plugin/plugin_*.vim (per-plugin configuration) files. See the
MyVim Quickstart for the full
walkthrough.
" With confirmation
:PluginManager remove fugitive
" Force remove without confirmation
:PluginManager remove surround -f" List all installed plugins
:PluginManager list
" Show status of all plugins
:PluginManager status
" Update all plugins
:PluginManager update
" Update a specific plugin
:PluginManager update vim-fugitive
" Check for available updates without installing them
:PluginManager check
" Show a summary of all plugin changes
:PluginManager summary
" Generate helptags for all plugins
:PluginManager helptags
" Generate helptags for a specific plugin
:PluginManager helptags vim-fugitive
" Reload a specific plugin
:PluginManager reload vim-fugitive
" Reload all Vim configuration
:PluginManager reload
" Run a health diagnostic (checks git, Vim version, async, encoding, etc.)
:PluginManager health
" Collect submodules that are no longer declared in the vimrc
:PluginManager gc
" Same, without the confirmation prompt
:PluginManager gc -f" Commit any changes to vimrc, custom configurations, and new plugins, then push to all remotes
:PluginManager backup
" Reinstall all plugins from .gitmodules
:PluginManager restore
" Add a new backup repository
:PluginManagerRemote https://github.com/yourusername/vim-config-backup.gitThe backup command will:
- Copy your main configuration file (
.vimrc) into your.vimdirectory to ensure it's versioned along with everything else - Commit all changes in your Vim configuration directory, including:
- Your custom plugin configurations in the
plugin/directory - Any modifications to settings in
ftplugin/,syntax/,colors/, etc. - New or modified mappings and commands
- Any file not excluded by
.gitignore
- Your custom plugin configurations in the
Note that while your own configuration files are backed up, changes inside plugin submodules themselves won't be included in the backup - these are tracked separately as Git submodules pointing to specific commits.
Important Security Note: Never store sensitive information (API keys, GPG keys, tokens, passwords) in your versioned configuration files. Instead:
-
Create separate configuration files for secrets:
~/.vim/plugin/fugitive-secrets.vim ~/.vim/plugin/api-secrets.vim ~/.vim/plugin/private-settings.vim -
Exclude these files in your
.gitignore:# Ignore secret configuration files plugin/*-secrets.vim plugin/private-*.vim -
Or use a private repository if your entire configuration contains sensitive information
-
You also can reference external files from your main configuration:
" In your .vimrc
if filereadable(expand("~/api-secrets.vim"))
source ~/api-secrets.vim
endifPluginManager can check whether your plugins have updates available. The check
runs a background git fetch for each plugin and reports the ones that are
behind their remote branch in the sidebar.
All of this is opt-in and disabled by default: PluginManager never performs network access on startup unless you explicitly enable it.
" Check on demand (manual)
:PluginManager checkTo check automatically when Vim starts, enable it in your vimrc:
" Check for available updates on startup (default: 0/off)
let g:plugin_manager_check_on_startup = 1
" Hours between background checks; results are cached to avoid
" re-fetching on every launch (default: 24)
let g:plugin_manager_check_interval = 24
" Automatically install available updates on startup (default: 0/off)
" Implies check_on_startup behavior; honors pull_strategy and
" auto_commit_on_update.
let g:plugin_manager_auto_update = 1When check_on_startup is enabled, PluginManager caches the last result and
only performs a new network fetch once check_interval hours have elapsed. With
auto_update enabled, available updates are installed in the background after
the check completes.
" Toggle the plugin manager sidebar
:PluginManagerToggleq- Close the sidebarc- Check for available updatesl- List installed pluginsu- Update all pluginsh- Generate helptags for all pluginsH- Run health diagnostics- Show status of submodulesS- Show summary of changesb- Backup configurationr- Restore all pluginsR- Reload configuration?- Show usage information
cd ~/.vim
git remote rename origin genesis
git remote add origin your_repository_url
# Optional: Add backup repositories
git remote set-url origin --add --push second_repository_url
git remote set-url origin --add --push third_repository_urlYou can customize the plugin manager by setting the following variables in your vimrc:
" Custom Vim configuration directory
let g:plugin_manager_vim_dir = '~/.vim'
" Custom plugin directory
let g:plugin_manager_plugins_dir = '~/.vim/pack/plugins'
" Custom directory for auto-loaded plugins
let g:plugin_manager_start_dir = 'start'
" Custom directory for optional (lazy-loaded) plugins
let g:plugin_manager_opt_dir = 'opt'
" Custom vimrc location
let g:plugin_manager_vimrc_path = '~/.vim/vimrc'
" Custom sidebar width (default: 80)
let g:plugin_manager_sidebar_width = 80
" Spinner style and refresh interval (ms) for the non-blocking UI
let g:plugin_manager_spinner_style = 'dots' " dots, line, circle, triangle, box
let g:plugin_manager_spinner_interval = 80
" Default git host for short plugin names
let g:plugin_manager_default_git_host = 'github.com'
" Git pull strategy for updates: 'ff-only' (default), 'merge', or 'rebase'
let g:plugin_manager_pull_strategy = 'ff-only'
" Automatically commit submodule pointer changes after updates (default: 1)
let g:plugin_manager_auto_commit_on_update = 1
" Maximum number of concurrent async git jobs (default: 4)
let g:plugin_manager_max_concurrent_jobs = 4
" Timeout in seconds for a single async job (default: 60)
let g:plugin_manager_job_timeout = 60
" Update notifications (all opt-in, default off)
let g:plugin_manager_check_on_startup = 0
let g:plugin_manager_check_interval = 24
let g:plugin_manager_auto_update = 0
" Debugging and diagnostics (default off)
let g:plugin_manager_debug_mode = 0
let g:plugin_manager_trace_commands = 0
let g:plugin_manager_show_deprecation_warnings = 1Use the on and for options to install a plugin into pack/plugins/opt/
and load it at first use, exactly like vim-plug's on:/for::
PluginBegin
" Loads on the first NERDTreeToggle or NERDTreeFind invocation
Plugin 'preservim/nerdtree', {'on': ['NERDTreeToggle', 'NERDTreeFind']}
" Loads when a markdown buffer is opened
Plugin 'vimwiki/vimwiki', {'for': ['markdown']}
PluginEndThe first command invocation runs :packadd, then re-dispatches the command
(with range, bang and arguments) against the real one. Buffers already
showing a matching filetype when the block is processed load immediately.
Both options imply load: 'opt'.
Optional plugins without triggers are loaded manually:
:packadd plugin-nameThe options system allows for flexible plugin installation almost like junegunn/vim-plug:
" Install a plugin and specify a branch
:PluginManager add tpope/vim-fugitive {'branch': 'main'}
" Install a plugin to a specific directory and specific tag
:PluginManager add junegunn/fzf {'dir': 'myfzf', 'tag': 'v0.24.0'}
" Pin an exact commit
:PluginManager add fatih/vim-go {'commit': '47694979'}
" Install a plugin and execute a command after installation
:PluginManager add junegunn/fzf {'exec': './install --all'}Version precedence when several are declared: branch > commit > tag.
When updating plugins, PluginManager will stash any local changes in the plugin repositories. If you've made custom modifications to plugins, consider using a different approach like git patches.
Plugins pinned with tag or commit in the vimrc are not pulled: update
re-asserts the declared pin instead. Bump the tag in your vimrc, run
:PluginManager update, and the submodule moves to the new revision
(local changes are stashed and restored around the checkout, and the
submodule pointer is committed). See :help plugin-manager-pinning.
- Make sure your Vim configuration directory is a Git repository
- Check that you have write permissions to the plugin directories
- Verify the plugin URL is correct and accessible
- For 'start' plugins, ensure they're in the correct directory
- For 'opt' plugins, make sure you're using
:packaddto load them - Reload your vimrc after installing new plugins
- Most issues are related to Git submodule commands
- Run
:PluginManager statusto check the status of all modules - Try running
:PluginManager restoreto reinitialize all modules
For detailed documentation, use the :help plugin-manager command after installation.
Contributions are welcome! See CONTRIBUTING.md: fork +
branch + pull request (Conventional Commits, test-first, one squash merge per
PR). Every PR is squash-merged into main with its title as the commit message.
Bugs go through the bug report form.
PluginManager is released under the MIT License.
Copyright (c) 2018 - 2026 G.K.E. gke@6admin.io