Using Neovim for software development
I love coding, and I love using Neovim to do it. In this article, I hope to inspire and make it
easier for other developers to consider Neovim for software development. Who knows, maybe
you will love it too.
A little background
I've been a professional software developer for over 20 years, but I haven't always used vim for
programming.
I got my first taste of vim in college as I was studying computer science. I had a professor there
who was a true vim master. I recall staring up at his screen as he jumped around and edited
code with god-like omnipotence. At the time, I had no idea what combination of keys he was
pressing to make the editor bend to his will with such minimal effort, but I wanted that power.
I used vim for coding throughout college, and I was getting pretty good at it. Then, sadly, I
stopped using it when I started my first programming job. During this phase of my life vim was
relegated to note taking and editing text files from the terminal. After using full-blown editors like
Eclipse for a while, I subconsciously came to the conclusion that vim could not compete in the
world of IDEs, and at the time perhaps that was true.
About ten years into my career, we hired a new guy at the place I was working. I was shocked
to see that he used vim exclusively for the Ruby on Rails development we were doing at the
time. For the second time in my life, I was inspired by someone else's display of vim prowess. I
had never stopped enjoying the limited opportunities I had to use vim, so I was super excited at
the prospect of using it full-time for development. So that's what I did, and, for the most part, I
have been using it as my main code editor ever since.
Why bother learning vim
Vim is a modal editor which means it has more than one mode of operation. The two primary
modes are "insert" and "normal". Insert mode behaves like regular text editors where the keys
you type are written into the document. Normal mode is used for moving around the file (moving
the cursor within the file) and executing commands against the text within the file. Because
normal mode is distinct from insert mode, every key on the keyboard is available to perform
operations. This is what enables the efficiencies in vim because powerful movements can be
achieved without ever having to move your hands off of the home row on your keyboard. The
following table gives just a few examples of these efficiencies. Try for yourself and see how
much nicer the vim mappings are.
It may take a little while, but once you get used to vim mappings, having to use arrow keys,
specialized keys like home/end, contorting your fingers to press complex combinations of
modifiers, or even using the mouse feels very tedious.
Vim has so many commands to improve editing speed; even though I have been using vim for
over 20 years, I am still learning new things regularly. It's always fun when one vim user is
watching another vim user and says something like: "Wait, why did you do that? You know you
can just do ...". I have learned and taught many vim tricks this way.
I know people can get extremely fast with modeless editors using mappings like those in the
second column of the table above. I know many are even much faster than me using vim.
However, my claim is that vim offers the highest upper bound of speed for any given person.
Two ways to leverage Vim for coding
There are two levels of adoption when it comes to using Vim for software development.
The first level is turning on vim mode/emulation in your current IDE (e.g. Visual Studio Code).
Most IDEs support this at some level. For Jetbrains products, the Ideavim plugin is excellent. I
think everyone should at least try this first level of adoption. In fact, one could argue that you
get the best of both worlds with this approach: the efficiencies of modal editing and vim
movements/commands as well as all of the bells and whistles of a full blown IDE. I, personally,
would not make this argument, but I certainly understand the position.
The next level is actually using Neovim (or Vim) as your IDE. I.e. literally opening up a terminal,
changing directories to your project and running the command, nvim. So fun.
Vim has come a long way since I started using it in college and Neovim takes it to the next
level. There are tons of quality plugins, and the available plugin managers make it simple to
start using them. Configuration and customization are also much better now since Neovim
supports using Lua for scripting.
The following sections are mainly for those who want to go all the way and use Neovim as their
IDE.
Installation and config
Installation of Neovim is straightforward. Just follow the instructions on the installation page.
Neovim is highly configurable with hundreds of options that can be set, limitless mapping
possibilities, and flexibility in creating custom commands and functions. Because of this, it's
easy for your configuration to get a little messy. It is worth taking some time at the beginning
and periodically to keep things organized and trimmed down. A clean configuration is like a
clean room, it's more enjoyable to be in.
Describing the options, how to do mappings, and how to create custom
commands/functions is out of scope for this article but I recommend learning about these
things from the Neovim documentation.
The entry point for your configuration in Neovim is the init.vim (or init.lua) file. I
recommend going with Lua instead of vim's native script. I prefer using Lua, especially if I plan
to do any complex scripting. The following table lists the standard location to create your
init.vim or init.lua file.
Env Location
I like to break up my configuration into multiple files to help me keep things organized. Including
separate files from your init.lua file can be done with statements like the following:
Note: this loads a file located at <config_root>/lua/core/options.lua then runs the
config() function from the loaded module.
Here is what my config structure looks like, but do what makes the most sense to you.
- .config/nvim: config root
- lua/: the root folder of any lua files you want to include
- core/
- autocommands.lua: where I define custom autocommands
- mappings.lua: where I define my key mappings
- options.lua: where I set options to my liking
- custom/: lua files where I create custom functions/commands
- plugins/: plugin configuration (I use lazy.nvim as my plugin manager)
- core/
- init.lua: entry point for the config
- lua/: the root folder of any lua files you want to include
I also recommend creating a git repo on GitHub or a similar site to house your configuration.
This makes it quick and easy to get your Neovim configuration set up on new computers.
Must-have plugins
To this point we've talked about using vim in a general sense, but to really use it effectively as
an IDE for software development, you will likely want to install some plugins.
Plugin management, including installing and uninstalling, enabling and disabling, configuring,
and upgrading, is a common activity when using Neovim as your IDE, especially when you are
first starting out. To make this as seamless as possible, use a good plugin manager. There are
multiple options, but I like to use lazy.nvim. It has been working great for me.
Staples
Here are some general purpose plugins that are staples for a lot of vim users.
- surround: provides mappings to easily delete, change and add surroundings (parenthesis,
brackets, quotes, xml tags, etc) in pairs - vim-repeat: enhances functionality of the vim repeat command (.) so that multi-step edits
provided by plugins can be repeated - vim-easymotion: enhances some vim motions to provide super efficient movements
- snacks: This is actually a collection of quality-of-life plugins for Neovim. Pick and choose
the ones that bring you joy.
Coding assistance
Some of the most important features of an IDE are related to code assistance; these include
things like syntax highlighting, autocompletion, jump to definition, error and warning indicators,
and refactoring support.
Here are some must-have plugins to bring these features into your Neovim setup.
- nvim-treesitter: along with the tree-sitter executable, enables syntax parsing to provide
syntax highlighting, code folding, and structural navigation for any programming language
you might want to use - nvim-lspconfig: Neovim comes with built-in support to act as an LSP (language server
protocol) client. The nvim-lspconfig plugin provides default configurations to simplify the
setup of LSP servers. - mason: Although nvim-lspconfig provides default configurations for LSP servers, you still
need to install and run the external LSP server executables. The mason plugin is a
package manager for external tools such as LSP servers, DAP servers (for debugging),
linters, and formatters. - nvim-cmp: a completion engine to support autocomplete from various sources such as
LSPs and snippets - trouble: a pretty list for showing diagnostics, references, telescope results, quickfix and
location lists - copilot: for if you want copilot integration (AI completions)
- nvim-dap & nvim-dap-ui: plugins to support debugging in Neovim
File navigation
Another set of features that all IDEs need to support is related to file navigation such as finding
and opening files, finding files containing text, viewing and navigating the file tree, etc. With the
following plugins Neovim can be configured with amazing support for these types of features.
- neo-tree: file system browser
- oil: The oil plugin allows editing the file system like a normal Neovim buffer. Neotree
supports file system edits as well but using the oil plugin for this is so intuitive and fun to
use. - telescope: highly extensible fuzzy finder used for finding files by name, finding files
containing text, finding files in the current git commit, finding symbols within the current file, finding files based on open buffers, and much more
Git
Here are some must-have plugins to enable git integration in Neovim.
- vim-fugitive: the de facto plugin for git integration
- git-gutter: adds contextual git info at the line level in the gutter (left margin of the editor)
- snacks/lazygit: This plugin is part of the snacks collection of plugins mentioned above. It
provides Neovim integration to a tool called lazygit which is an awesome terminal UI
program that makes working with git repositories very simple. I usually end up using
lazygit over vim-fugitive. Note, you will need to install lazygit separately.
Tips
This section contains some tips and advice that I have acquired over the years.
Mappings
Because vim is a modal editor, as we discussed above, there are a lot of options when it comes
to key mapping; you don't always need to use modifiers like control or alt. A large number of the
mappings you create will likely be of the form <leader> followed by some character. For
example, I use <leader>f to open telescope (see plugins above) for find-in-files. The default
leader key in vim is backslash which is not the easiest key to press. It is pretty common to
change this to something more convenient like comma.
If you need to set up a lot of mappings, you can consider setting up a bunch of them in the form
of <space> followed by some character. This is also a common practice.
Mappings are, of course, great, but I suggest not being too quick to create them. The more
mappings you create, the harder it is to remember them. Also, you end up using all the good
mappings and run out of options when you need to add more. For a lot of things I like to use the
default binding or run the command directly. For example, I sometimes want to open the current
buffer in a new vertical split but I have never felt the need to create a custom mapping to do it.
Running the command directly with :vs<CR> has not been a problem. However, if opening a
vertical split is something you do all of the time in your normal workflow then make a mapping
for it.
Another widely used key by vim users is the ESC key. This is the key to get you back into
normal mode from insert mode, so you can imagine how often you would use it. Many users
also feel that the ESC key is not easy enough to press for as often as you need to. A common
alternative is to map jk and kj to ESC. This essentially allows you to mash j and k at the
same time to trigger the ESC key and return to normal mode. Another option is to alter the key map of your keyboard so
that the caps lock key is mapped to the ESC key. This is the option I use, but it does require being able to configure your
keyboard to change the key mapping.
Macros
Get good at macros. With macros you start a recording which logs all of your key strokes to a
register, then, when you are done performing key strokes, stop the recording. At this point you
now have a macro that you can run over and over again. It is amazing how powerful this can
be. You will definitely impress your pairing partner if you master this technique.
Relative line numbers
Turn on relative line numbers (set rnu). When you turn this on, the line numbers in the gutter
are relative to the cursor’s current position. If you also set regular line numbering (set nu), the
cursor's current line will display the actual line number within the file. This looks a little strange,
but it makes it much easier to calculate jump distances. For example if I want to jump
backwards to a line that is 5 lines up I can issue the command 5k. Try it for a while, I'm sure
you will like it.
Upgrade often
Stay up to date with the latest Neovim version and your plugin versions. If you do this often, it
makes it easier to isolate any problems that might arise from a new version. Using plugins like
nvim-treesitter and mason as well as a good plugin manager like lazy.nvim make upgrading
plugins and tools simple.
Keep learning
Neovim has so many features to offer. Keep reading the docs and experimenting with new
things like using marks, the global command, using tabs and splits effectively, diffing, folds, the
quickfix list, and much much more.
Pair Neovim with some additional tools
Since Neovim is a program that runs in the terminal, you will be spending a lot of time there. It's
worth upgrading your experience with a good terminal emulator. I have been using kitty for a
while now and I like it but, there are other good options as well. I am actually going to try out a
newer one called ghostty and see how I like that.
Another tool I've grown to love that pairs very well with development in a terminal with Neovim
is tmux. Tmux is a terminal multiplexer. I use it to create and manage terminal sessions,
windows, and panes. For example, within a single terminal instance, I can set up a handcrafted
workspace that contains all the windows and split panes I need for my development needs.
Navigating around all of the windows and panes in tmux is done with key mappings, so it lines
up well with the same mentality as in vim which is to increase productivity by allowing the user
to keep their hands on the keyboard as much as possible.
Actually, there are a lot of really neat terminal UI style programs out there that can enhance
your terminal experience. For example, as I mentioned before, lazygit is a very good terminal UI
for interacting with git. I encourage you to look for these things and really embrace using the
terminal more.
Closing
I sometimes get asked why I use Neovim, tmux, and similar tools in the terminal instead of a
"real" IDE. It's actually a hard question for me to answer because, comparing feature by feature,
my Neovim setup probably comes up short. I think it comes down to an intangible quality, a
feeling that you just can't appreciate until you try it for yourself. I hope you will.
John Quagliata
Connect with the author