Vim is a customizable and fast editor. The ability to adapt Vim to your needs makes it a very powerful tool.

Vim is for power-users and tinkerers. It uses less resources than modern alternatives like VS Code. You can use it without a mouse. That’s why you can edit text at “the speed of thought”.

The editor’s basic functionality already covers a lot of ground.

You can see it in action in this Youtube video:
How to Do 90% of What Plugins Do (With Just Vim)

Still, sometimes you want to enhance your experience with a plugin.

vim-packager is a minimal package manager for Vim 8 and NeoVim. It’s written in pure VimScript and thus needs no external dependencies.

vim-packager uses Vim’s native jobs and pack features. It sports an informative window when you use it:

vim packager preview

image from the vim-packager GitHub Readme

How Does Package Management Work in Vim?

What are packages? What exactly are plugins?

Let’s define some vocabulary:

I’ve been using the word “plugin” to mean “a big ol’ hunk of Vimscript that does a bunch of related stuff”. Vim has a more specific meaning of “plugin”, which is “a file in ~/.vim/plugin/”.

The folder ~/.vim/plugin loads all plugins every time you start the Vim editor.
Vim also has a directory ~/.vim/autoload. Vim delays the loading of a plugin located in that folder.

Unfortunately, adding a plugin that consists of more than one file requires you to manually add the code to Vim’s runtime path. That’s cumbersome.

In newer versions of Vim, the authors added a native package feature (see :h packages) which makes plugin management easier. It also supports lazy-loading.

You can find a guide here or here.

Updating plugins is still a hassle because you have to update each plugin yourself (or write your own script).

vim-packager

Kristijan Husak’s vim-packager adds a convenience wrapper around the native package management. It offers some additional features that make package management frictionless.

Find the installation instructions on GitHub and clone the repository to your computer.

For example, for NeoVim on Mac/Linux:

git clone https://github.com/kristijanhusak/vim-packager ~/.config/nvim/pack/packager/opt/vim-packager

Create your configuration (~/.vimrc, ~./config/nvim/init.vim or similar) according to the GitHub instructions:

" Only for Vim, NeoVim sets nocompatible automatically
if &compatible
  set nocompatible
endif

" Load packager only when you need it
function! PackagerInit() abort
  packadd vim-packager
  call packager#init()
  call packager#add('kristijanhusak/vim-packager', { 'type': 'opt' })
  call packager#add('junegunn/fzf', { 'do': './install --all && ln -s $(pwd) ~/.fzf'})
  call packager#add('junegunn/fzf.vim')
  call packager#add('vimwiki/vimwiki', { 'type': 'opt' })
  call packager#add('autozimu/LanguageClient-neovim', { 'do': 'bash install.sh' })
  call packager#add('morhetz/gruvbox')
  call packager#local('~/my_vim_plugins/my_awesome_plugin')

  "Provide full URL; useful if you want to clone from somewhere else than Github.
  call packager#add('https://my.other.public.git/tpope/vim-fugitive.git')

  "Provide SSH-based URL; useful if you have write access to a repository and wish to push to it
  call packager#add('git@github.com:mygithubid/myrepo.git')

  "Loaded only for specific filetypes on demand. Requires autocommands below.
  call packager#add('kristijanhusak/vim-js-file-import', { 'do': 'npm install', 'type': 'opt' })
  call packager#add('fatih/vim-go', { 'do': ':GoInstallBinaries', 'type': 'opt' })
  call packager#add('neoclide/coc.nvim', { 'do': function('InstallCoc') })
  call packager#add('sonph/onehalf', {'rtp': 'vim/'})
endfunction

function! InstallCoc(plugin) abort
  exe '!cd '.a:plugin.dir.' && yarn install'
  call coc#add_extension('coc-eslint', 'coc-tsserver', 'coc-pyls')
endfunction

command! PackagerInstall call PackagerInit() | call packager#install()
command! -bang PackagerUpdate call PackagerInit() | call packager#update({ 'force_hooks': '<bang>' })
command! PackagerClean call PackagerInit() | call packager#clean()
command! PackagerStatus call PackagerInit() | call packager#status()

"Load plugins only for specific filetype
"Note that this should not be done for plugins that handle their loading using ftplugin file.
"More info in :help pack-add
augroup packager_filetype
  autocmd!
  autocmd FileType javascript packadd vim-js-file-import
  autocmd FileType go packadd vim-go
augroup END

"Lazy load plugins with a mapping
nnoremap <silent><Leader>ww :unmap <Leader>ww<BAR>packadd vimwiki<BAR>VimwikiIndex<CR>

Now you can run the Vim command :PackagerInstall.

Updating all packages is as easy as running the :PackagerUpdate command.

Sweet!

Tips & Tricks

If you want to load several plugins conditionally or load plugins for several filetypes, you can chain the commands like this:

" Load plugins only for specific filetype
augroup packager_filetype
  autocmd!
  autocmd FileType dart packadd awesome-flutter-snippets | packadd vim-lsc-dart
  autocmd FileType html,eelixir packadd emmet-vim
end

This works for plugins that you installed with { 'type': 'opt' }. Otherwise the plugins are installed into the start folder and loaded automatically every time.

Further Reading