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.
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.
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.
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.
Git
Here are some must-have plugins to enable git integration in Neovim.
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.