Configuring Neovim from Scratch + Setting up Ubuntu

Kevin Feng
Nerd For Tech
18 min readMar 14, 2023


If there’s one thing that you should know about me, it’s that I love Visual Studio Code. My passions, hobbies, and personality can be thrown out the window. As long as you know that I love VS Code, then you have a pretty good idea of who I am.

VS Code Logo
Visual Studio Code

Visual Studio Code is an amazing text editor (it is not an IDE, fight me) built on Electron for Windows, Linux, and MacOS. It has tons of features, including integrated Git, syntax highlighting, code completion, and most importantly, a rich network of extensions. If you head over to the VS Code marketplace, you’ll be sure to find an extension that makes your code editor just a bit more perfect for your needs. Whether you want a code formatter that makes sure your code looks pretty after every time you save or a set of autocompletion code snippets for React hooks, VS Code is sure to have your back.


One of my favorite VS Code extensions is the VSCodeVim extension, which emulates Vim inside of Visual Studio Code. Once you install it, you’ll be able to jump up and down lines with k and j, enter insert mode with i, and do all of the fancy stuff that Vim fanatics achieve with just their keyboards.

The nice part about using Vim inside of VS Code is that you still have access to the entirety of the VS Code marketplace for its extensions, and disabling the Vim extension is as simple as toggling it off from the VS Code command palette.

I’ve been using Vim inside of VS Code for about a year now, and it’s been a great way to learn basic Vim commands and prevent myself from reaching for my mouse too often. But as cool as the extension is, the whole experience has felt a little tacky. I often found myself disabling the Vim extension when I was short on time (to make it faster to copy and paste code, obviously), and even while I used it, I always knew that in the back of my mind, I was angering the many pure Vim elitists in the world.

Well here I am to anger them even more, since I decided to start learning how to use Neovim, an improved and more modern version of Vim that was released in 2014. For the most part, Neovim is exactly like Vim, but has a much wider range of plugins, since you can configure the text editor not only with Vimscript, but also with Lua, which is a lightweight, multi-paradigm language, meaning it supports OOP, functional programming, procedural programming, etc.

But installing Neovim on my Windows machine might not be the best idea, since Linux is traditionally what is used with Neovim. The documentation, guides, and features of Neovim are all suited for Unix machines. Besides, as I read over job applications or just look over documentation for APIs while I’m building a project, it’s very apparent how prevalent Linux is. According to some Linux statistics from TrueList, almost half of all professional developers use Linux, over 96% of the top one million web servers run Linux, and the world’s top 500 fastest super computers all run on Linux.

Linux sure does power a lot of websites

Essentially, Linux runs the computer world, and it’s definitely not a bad idea to learn it if you have an interest in computers in any capacity. So I decided to kill two birds with one stone and set up a Linux virtual machine as well as set up Neovim.

Setting up a Linux distribution (Ubuntu)

Though I’ve used Linux before (primarily through SSH and some virtualization), I wouldn’t say I have an in-depth understanding of it. After reading a few Reddit threads and Quora posts, I decided that it would be best to start learning Linux via distributions that I could run locally on my computer through a virtual machine.

Though you can browse forums and find countless arguments about which Linux distro is the best, Ubuntu is very user-friendly and comes with a lot of features right out of the gate, so it’s a great choice for Linux beginners. I am aware that more advanced distros like Arch Linux and Gentoo Linux are better options for taking full advantage of Linux, but that being said, these distros require lots of knowledge on hardware as well as Linux itself for just the setup process, so it might not be the best idea to jump into those immediately. And for those who want the ultimate challenge, I would look into setting up Linux entirely from scratch. Until then, here’s how you can set up Ubuntu 22.04 via VMware Workstation on a Windows machine.

First, navigate to the VMWare Workstation downloads section for Workstation Player and download the installer.

Next, locate the Ubuntu 22.04 iso file and download that as well.

The iso file might take quite a while to download (it’s almost 5 GB as far as I can tell), but once that’s done, open up the VMWare Workstation installer. You should see something like this while the application prepares for the install:

You might have to restart your computer to finish the Microsoft VC Redistributable installation, so if that’s the case, restart your PC and rerun the installer. You should now see the setup wizard:

Click “Next” and then hastily accept the terms and conditions without reading anything as per usual…

If you see the following screen, check the box to install WHP (this part may not show up as it is dependent on your device).

On the next screen, you don’t need to change anything, unless you are using an international keyboard or are using a keyboard with extra keys.

For the user experience settings, I would highly recommend checking the first box. Checking the second one just depends on if you care about certain data being sent during your usage of the virtualization software.

Hit “Next” again.

And you’re ready to install. This should only take a few moments.

Once it’s done, you can click “Finish” and there should be a VMWare Workstation Player icon on your desktop now.

Open up the software, and since we’re utilizing VMWare for non-commercial use, we continue with the first option.

Click “Finish” one more time and then you’ll be greeted with VMWare Workstation Player’s main dashboard. Let’s create a new virtual machine by selecting the first option in the menu on the right.

You will then be greeted with another wizard, this time to set up a new virtual machine. Browse your system’s files to find wherever you downloaded your Ubuntu iso (by default it should be in Downloads) and then selext “Next.”

Next up, we’ll be setting our username and password. Definitely don’t forget the password that you set. It won’t be as easy as resetting your password for your dog’s TikTok account.

You can name the virtual machine whatever you want, it doesn’t really matter.

The next part gets a little interesting. By default, the virtual machine wizard will have you split your virtual disk into multiple files, but there isn’t a huge difference. The first option will have better performance (not that you will notice it) and the second option is less of a hassle for file recovery (which also probably won’t be a problem).

Finally, we can create the virtual machine and power it on right away.

While you see Ubuntu getting set up, I would recommend practicing the default keybinds for focusing on the virtual machine as well as leaving focus for it. To focus on the virtual machine, just perform CTRL + G and to focus back on Windows, just perform CTRL + ALT. Simple enough.

While Ubuntu sets itself up, it will also prompt you with some preference settings. First, you’ll want to set your preferred language.

Then you’ll want to check off the option to install third-party software. I recommend a normal installation, but a minimal installation is fine as well. It will just end up requiring a bit more work from you for installing the software you want.

Lastly, you’ll want to install Ubuntu with the first option (don’t panic about your disk being erased, it’s not referring to your Windows OS).

While Ubuntu installs, you’ll get this cool menu for selecting your time zone:

And lastly, you’ll get a screen to set up your username and password for Ubuntu itself.

After a few minutes, Ubuntu should be installed, and it will require a restart of the virtual machine in order to be used.

After you restart, you’ll find the user that you created. Log in, and you’ll finally have access to Ubuntu!

Installing Neovim, Thrice

Now that we’ve got access to a Linux machine, let’s install Neovim. I messed around with the different installation methods (because there are quite a few) and found three different methods that all result in different versions of Neovim. Depending on what plugins or features you want to take advantage of, you might want to run at least a certain version (many plugins or features require at least Neovim 0.7).

Here’s the first one, which installed Neovim v0.6.1 for me. Simply open a new terminal with CTRL + ALT + T and execute this command:

sudo apt install neovim

And that’s it! You can test out default Neovim right away with nvim or a command like nvim example.txt to create a text file that you can edit.

I’m not sure if it was supposed to, but performing sudo apt update did not help the APT package manager to install a newer version of Neovim.

The second method is almost as simple as the first one; you’ll only have to execute two commands:

sudo add-apt-repository ppa:neovim-ppa/stable
sudo apt update

This installed Neovim v0.7.2 for me. You can also navigate to this page if you want to do a little bit of reading regarding the PPA (Personal Packaged Archive, or software that is bundled and designed for Ubuntu users).

Now the last method is far more complex and time-consuming, but it does install Neovim v0.9.0. I was able to do this by building the software from the source code. There are a lot of steps here, but it’s summarized quite well on Neovim’s wiki page here.

The first step is to install build prerequisites. In general, any system will need these two requirements:

  • Clang or GCC version 4.9+
  • CMake version 3.10+, built with TLS/SSL support

So let’s start by installing GCC and CMake. For GCC, it’s pretty straightforward. In a terminal, you’ll want to execute these commands:

sudo apt update
sudo apt install build-essential
sudo apt-get install manpages-dev

Afterwards, you can run

gcc --version

to check whether or not it installed properly. So long as the version is at least 4.9, you’re good to go.

For CMake, I found a very helpful guide on this Ask Ubuntu forum. First, you’ll want to ensure that the default version of CMake is removed from Ubuntu with

sudo apt remove --purge --auto-remove cmake

Next up, you’ll want to prepare your system for installation of CMake:

sudo apt update && \
sudo apt install -y software-properties-common lsb-release && \
sudo apt clean all

Then we’ll get a copy of Kitware’s signing key:

wget -O - 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null

Next we’ll add Kitware’s repository to our sources list:

sudo apt-add-repository "deb $(lsb_release -cs) main"

Though this next step is optional, I decided to run it. This ensures that Kitware’s keyring stays up-to-date if keys are rotated.

sudo apt update
sudo apt install kitware-archive-keyring
sudo rm /etc/apt/trusted.gpg.d/kitware.gpg

We then copy the public key 6AF7F09730B3F0A4:

sudo apt-key adv --keyserver --recv-keys 6AF7F09730B3F0A4

And finally, we install CMake:

sudo apt update
sudo apt install cmake

Once again, make sure to run

cmake --version

to confirm that you have installed a version of CMake that is at least on version 3.10.

Now that we have the general system prerequisites out of the way, we’ll need to install Ubuntu specific requirements, which Neovim provides on their wiki. Run this command to install those requirements:

sudo apt-get install ninja-build gettext libtool-bin cmake g++ pkg-config unzip curl

After all of that, we’ve only installed all the build prerequisites… Don’t worry, we’re actually almost done! Fair warning: Some of the final commands take some time to run, so if you notice that a command is taking longer than just 5 or 10 seconds, feel free to let it finish in the background while doing something else.

For step 2, we’ll need to clone the Neovim repository to our virtual machine. Do this somewhere that is easy to access; I personally changed the directory of my terminal to my desktop first, and then executed this command:

git clone

If you’ve also done this on your desktop, you should now see a folder called “neovim” on your desktop. From here, we can either install the latest version or the latest stable version. Regardless of which one you want, first run

 cd neovim && make CMAKE_BUILD_TYPE=RelWithDebInfo 

to change directories into the cloned source code of Neovim and run CMake on it. If you want the latest stable version, make sure to also run

git checkout stable

Lastly, just run

sudo make install

And we’re finally done! Neovim may or may not open on its own after running sudo make install:

Now for the issue of quitting Neovim…

Good meme, definitely not overused

Just kidding! I’m not cruel enough to leave you trapped inside this seemingly inescapable text editor! Just use :q to quit out of Neovim.

Now you might notice that the nvim command doesn’t work; this happened to me after building the project from its source code. No need to panic, just open up your file explorer, perform CTRL + L to simultaneously focus on the current directory and highlight everything, and replace it with this:


You should see something like this:

You’ll want to open a terminal at this directory, which you can conveniently do from the file explorer if you click the three little dots next to the address bar and select “Open in Terminal.”

Once your terminal is open, execute this command


and you’ll see Neovim open up again. However, this time when you exit with :q, the nvim command should start working when you use it in the terminal. If nvim alone still doesn’t work, try running sudo nvim. If that works, then try to change the permissions of the Neovim executable like so (while your terminal is at /usr/local/bin:

sudo chmod u+x nvim

Basic Neovim Configuration

We can finally start configuring Neovim now! Keep in mind that some features or plugins might not work depending on the version of Neovim that you’ve installed; I recommend the third version of installation to get Neovim v0.9.0 by building it from the source code.

Just before we create our config file, I want to mention that running

sudo apt install wl-clipboard

will make it such that you can perform "+y to yank from Neovim to your system clipboard and "+p to paste from your system clipboard into Neovim. Pretty useful when you need to copy and paste code snippets.

To create our config file, we need to first get to the proper directory. In a terminal, execute

cd ~/.config
mkdir nvim

to create a folder named “nvim” in the config folder. Next, let’s create our config file with

cd nvim
nvim init.lua

Once inside our config file, let’s write a few things down:

Remember to use the i key to enter insert mode and ESC to exit insert mode

To test this out, we can write to the file (save our changes) with :w and also source % to compile. You should now see line numbers on the left side of Neovim.

This is a great starting point for a Neovim config, but if we want to take advantage of Lua scripting, then we’ll want to modularize our Neovim plugins and configuration structure.

Installing Plugins

Feel free to customize your config structure to whatever you like, but if you want to copy what I did, set up your directory like this:

📂 ~/.config/nvim
├── 🌑 init.lua
├── 📂 lua
│ ├── 📂 v9
│ ├── 🌑 keymaps.lua
│ └── 🌑 plugins.lua

You’ll want to move all the code from init.lua to keymaps.lua and simply replaced the entirety of init.lua with


Don’t forget to use :source % to compile your changes! If everything is still working, let’s get to installing Neovim plugins via packer.

Create a plugins.lua file, where we’ll call on packer to help us install plugins for Neovim. We’re going to be using the bootstrapping method for packer, so copy the following code

local ensure_packer = function()
local fn = vim.fn
local install_path = fn.stdpath('data')..'/site/pack/packer/start/packer.nvim'
if fn.empty(fn.glob(install_path)) > 0 then
fn.system({'git', 'clone', '--depth', '1', '', install_path})
vim.cmd [[packadd packer.nvim]]
return true
return false

local packer_bootstrap = ensure_packer()

return require('packer').startup(function(use)
use 'wbthomason/packer.nvim'
-- My plugins here
-- use 'foo1/bar1.nvim'
-- use 'foo2/bar2.nvim'

-- Automatically set up your configuration after cloning packer.nvim
-- Put this at the end after all plugins
if packer_bootstrap then

into plugins.lua. You’ll also want to add


in your init.lua file. If we run :PackerSync after writing all of our changes, we should get another Vim buffer on the left side of our terminal based on the plugins that we’ve added to plugins.lua. For example, if you add

use 'ellisonleao/gruvbox.nvim'
use 'nvim-tree/nvim-tree.lua'
use 'nvim-tree/nvim-web-devicons'
use 'nvim-lualine/lualine.nvim'

where plugins.lua reads -- My plugins here, then running :PackerSync should install those plugins (in the screenshot below, I’ve already installed gruvbox, so packer only shows the other three being installed).

Configuring Plugins

Now that we’ve installed some plugins, let’s take advantage of our file hierarchy and create .lua files for each plugin in a modular fashion. Get your directory to look like this by using mkdir and touch for creating folders and files, respectively:

📂 ~/.config/nvim
├── 🌑 init.lua
├── 📂 lua
│ ├── 📂 v9
│ ├── 🌑 keymaps.lua
│ └── 🌑 plugins.lua
│ └── 📂 plugin_config
│ ├── 🌑 gruvbox.lua
│ └── 🌑 lualine.lua
│ └── 🌑 nvim-tree.lua

Here is the code for each plugin config file:

After writing each plugin configuration, we’ll want to create another init.lua file, but this time, it will be in the plugin_config directory. Here’s the full file structure to leave out any ambiguity (the new init.lua is in bold):

📂 ~/.config/nvim
├── 🌑 init.lua
├── 📂 lua
│ ├── 📂 v9
│ ├── 🌑 keymaps.lua
│ └── 🌑 plugins.lua
│ └── 📂 plugin_config
│ ├── 🌑 gruvbox.lua
│ └── 🌑 lualine.lua
│ └── 🌑 nvim-tree.lua
│ └── 🌑 init.lua

In this new init.lua file, we’ll want to require all the config files that we just wrote up, so its contents should be:


Then in our original init.lua file (the one that is directly under ~/.config/nvim, we’ll want to require our plugin config, so now the entire file should look like:


If we run the nvim command, you should see that all of our plugins are working (hit CTRL + N to see nvim-tree)!

The obvious problem right now is that our font doesn’t support the symbols that our plugins are using. This is because we don’t have a Nerd Font installed. A Nerd Font essentially puts together a bunch of glyphs and symbols from different sources, including Font Awesome, Material Design, and Devicons to be compatible for a single font. Without a Nerd Font, we won’t be able to properly see the symbols in our nvim-tree or lualine plugin.

Installing a Nerd Font

To install a Nerd Font, we’ll want to visit the patched fonts section of the Nerd Fonts GitHub repository. You’ll see a long list of fonts to select from; I’ll be installing BigBlueTerminal, which is based off of the old IBM terminal characters (I’m a sucker for old school fonts).

Click on the font that you want to install and then click on the “complete” folder to reveal all the font files. You’ll typically only need the last file in the directory; it’s the standard “complete” version of the font. Most of the files will be .ttf files, but some will be .otf files. If you have the option, go for the .otf file, since it’s built off of the older .ttf file type (it’s typically better). After clicking on the font file, download it.

Now we’re going to want to move our downloaded font to the correct directory, which is /.local/share/fonts/NerdFonts . After changing directories to /.local/share, you’ll have to use mkdir to create fonts and its subdirectory, NerdFonts. Running pwd will print out your current working directory, which should show something like this:


To open a file explorer at this location, just execute nautilus . in your terminal. This should pop up:

From there, you can just drag and drop your installed font from Downloads into this new folder. Once you’ve done that, just right click anywhere on your terminal, open up “Preferences,” make sure “Custom font” is checked off, and open up your system’s list of available fonts by clicking “Monospace” (or whatever the current font of your terminal is).

Select your new font, mess around with the font size if you want, and click “Select” in the top right to confirm.

Now when you load up Neovim and check out your icons, like those found in nvim-tree, they should be working:

Our file tree explorer looks great!
Tux (the Linux penguin) even shows up in lualine!

And that’s pretty much it for this guide! In my opinion, this Neovim configuration is great, but not necessarily complete. The two biggest features that it’s missing right now are a terminal plugin and better syntax highlighting. Instead of guiding you through it, I’ll leave you to try implementing those on your own (just to get you started, I’d recommend checking out toggleterm and treesitter).

Adding additional plugins is pretty simple; just review the Installing Plugins and Configuring Plugins sections from earlier in this guide and try to replicate those steps for new plugins that you find on GitHub. If you’re confused on how to write up the config files themselves, be sure to reference the documentation of each plugin. Don’t forget that you can always use someone else’s config file as a starting point if you stumble upon one. Have fun!