Your Vim config, line by line
Your config is a plain text file your editor runs every time it starts: ~/.vimrc for Vim, ~/.config/nvim/init.lua for Neovim, settings.json for VS Code's Vim extension, ~/.ideavimrc for JetBrains IDEs. Open it from inside Vim with :e $MYVIMRC, add one line you understand, and reload with :source %. A dozen lines of your own beat a thousand copied ones.

| Editor | The file | Written in | Open it |
|---|---|---|---|
| Vim on macOS and Linux | ~/.vimrc (or ~/.vim/vimrc) | Vim script | :e $MYVIMRC |
| Vim on Windows | $HOME/_vimrc (or $HOME/vimfiles/vimrc) | Vim script | :e $MYVIMRC |
| Neovim on macOS and Linux | ~/.config/nvim/init.lua (or init.vim, never both) | Lua (or Vim script) | :e $MYVIMRC |
| Neovim on Windows | ~/AppData/Local/nvim/init.lua | Lua (or Vim script) | :e $MYVIMRC |
| VS Code (the Vim extension) | your user settings.json | JSON | Command Palette: Preferences: Open User Settings (JSON) |
| JetBrains IDEs (IdeaVim) | ~/.ideavimrc (or ~/.config/ideavim/ideavimrc) | Vim script, a subset | The IdeaVim icon in the status bar: Open ~/.ideavimrc |
Your dojo, your rules
All through the course you train in a dojo someone set up for you: numbers in the gutter, a few lines kept above the cursor, searches that ignore case. Your own editor is your own dojo, and the config is the list of rules on its wall. The editor reads it at every start and does what it says.
To open it, type :e $MYVIMRC in Vim or Neovim: $MYVIMRC holds the path of the config the editor loaded. No config yet? Then there's nothing to open, so make the file. In Vim, :e ~/.vimrc and :w. In Neovim, :exe 'edit' stdpath('config') .. '/init.lua', then :w ++p (the ++p makes the folder too). :echo $MYVIMRC tells you which file is in charge at any time.
- Neovim: Lua or Vim script.
init.luaandinit.vimboth work, one at a time. This guide shows both Vim script and Lua; the options are the same names in each. - Vim: one surprise. With no
~/.vimrc, Vim loadsdefaults.vim, which switches on syntax highlighting,incsearch,scrolloff=5and the mouse. The moment your own file exists, it doesn't. Keep them with two lines at the top:unlet! skip_defaults_vimandsource $VIMRUNTIME/defaults.vim. - Neovim starts friendlier.
hlsearch,incsearch, the mouse and syntax highlighting are already on, undo files already have a folder of their own (undofileitself still needs switching on), andtermguicolorsswitches itself on when your terminal can show true colour.
Build one, a switch at a time
The window below is Vim with an empty config, after a search for total. Each switch is one line in a config file: flip it and the window redraws the way that line would make it. Under the window, the file those switches add up to, in Vim script, Lua or VS Code's JSON, ready to copy.
Try number and then relativenumber, together and on their own, and watch what happens to your own line's number. Then flip ignorecase with hlsearch off and on.
" ~/.vimrc " nothing yet: Vim's defaults
The options worth having, and why
Each line below earns its place by fixing something you'd otherwise notice every day. Vim script first, Lua after.
- Where am I?
set number relativenumber(vim.opt.number = true,vim.opt.relativenumber = true). Your line shows its real number, for:42and error messages; every other line shows how far away it is, which is the count you type before j or k. - Searches that read your mind.
set ignorecase smartcase./totalfinds Total and TOTAL too; type a capital,/Total, and case counts again. - See every match.
set incsearch hlsearch: matches light up while you type the search, and stay lit after.:nohlsearch(or:noh) puts them out until the next search; Neovim already does both, and its Ctrl-l clears them. - See where you're going.
set scrolloff=8keeps eight lines past the cursor in view, so you never edit on the window's last row. - Long lines.
wrapis on by default: a long line folds onto the next screen row.set nowrapcuts it at the edge instead, which code readers often prefer. - Spaces, not tabs.
set expandtab shiftwidth=2 tabstop=2: >> and the Tab key put in two spaces, and a real tab character shows two columns wide. Use 4 if that's your project's style. - Undo that survives.
set undofilekeeps undo history after you close the file. In Vim, alsoset undodir=~/.vim/undo//(make that folder first), or the undo files land next to your code; Neovim already keeps them in its own folder. - The system clipboard.
set clipboard=unnamedplus(vim.opt.clipboard = "unnamedplus") makes y and p use the clipboard every other app uses. In Vim on macOS or Windows, useunnamed; Vim needs to be built with clipboard support (vim --versionshows+clipboard). - The mouse.
set mouse=alets you click, select and scroll in a terminal Vim. Neovim has it on already. - Splits where you look.
set splitbelow splitright::splitopens below and:vsplitto the right, as most apps do. - Real colours.
set termguicolorsin Vim, for colour schemes made for true colour terminals.
In Lua, an on/off option is true or false, a number is a number, and a word is a string: vim.opt.clipboard = "unnamedplus". Neovim's own example config writes vim.o.number = true; vim.o and vim.opt both work for these.
Write your first .vimrc
A config is a file like any other, edited with the same keys. Add set relativenumber on a new line below set number, change the tab width from 8 to 2, then add set expandtab shiftwidth=2 as the last line.
Stuck? Show the keys
o opens a line below and starts Insert mode; $ goes to the end of the line and r replaces one character.This editor needs a keyboard. Read on, and play it at your computer.
What relative numbers are for
With relativenumber on, the gutter shows 4 beside the return line, and your cursor is on the tax line. Which keys take you to return?
smartcase, with a capital
Your config has set ignorecase smartcase. The cursor is on the first line, and you search /Total (capital T). Where does the cursor land?
Set it, check it, reload it
Every option can be tried before it goes in the file: :set relativenumber switches it on in this editor until you quit. When it's what you want, write the same words in the config without the colon.
- Is it on?
:set number?answersnumberornonumber;:set scrolloff?answersscrolloff=0. - Who set it?
:verbose set scrolloff?also says which file and line last set it: the first thing to type when an option won't stay the way you wrote it (a plugin may have changed it). - Flip it.
:set number!turns it on if it's off and off if it's on;:set nonumberturns it off. - Reload.
:source %runs the file you're editing, so a change in your config takes effect at once (in Neovim, Lua files too). Deleting a line and reloading doesn't switch its option back off, though: restart for a clean slate. - Read about it.
:help 'scrolloff'(the quotes find the option) explains any option;:optionslists them all, with their current values. - When it breaks.
vim --cleanornvim --cleanstarts with no config at all, so you can always get in and fix the file.
Your config commands, from memory
Type each one as you would in Vim, Enter included, with option names in full.
Vim script and Lua, side by side
Neovim reads Lua, Vim reads Vim script, and the option names are the same in both. Once you can read one column below you can write the other. When there's no Lua spelling to hand, vim.cmd("set number") runs any Vim script line from Lua.
| To | Vim script (.vimrc) | Lua (init.lua) |
|---|---|---|
| Switch an option on | set number | vim.opt.number = true |
| Switch it off | set nonumber | vim.opt.number = false |
| Give it a number | set scrolloff=8 | vim.opt.scrolloff = 8 |
| Give it a word | set clipboard=unnamedplus | vim.opt.clipboard = "unnamedplus" |
| Set the leader key | let mapleader = " " | vim.g.mapleader = " " |
| Map a key in Normal mode | nnoremap <leader>h :nohlsearch<CR> | vim.keymap.set("n", "<leader>h", "<cmd>nohlsearch<CR>") |
| Map a key in Insert mode | inoremap jk <Esc> | vim.keymap.set("i", "jk", "<Esc>") |
| A comment | " like this | -- like this |
The leader key and your own mappings
A mapping makes some keys stand for others. The shape is the same everywhere: the mode, the keys you'll press, and the keys they stand for. inoremap jk <Esc> (Lua: vim.keymap.set("i", "jk", "<Esc>")) means: in Insert mode, typing j k quickly does Esc. It's the most popular first mapping, because your fingers never leave the home row.
Why `noremap`? The nore means the right-hand side is pressed as Vim's own keys, not through your other mappings. Swap ; and : with nmap ; : and nmap : ;, and each mapping feeds the other forever; with nnoremap they swap cleanly. Always use the noremap forms (nnoremap, inoremap, vnoremap) unless you mean to chain mappings. vim.keymap.set is non-recursive already.
The leader is a key that starts commands of your own, so they never land on a key Vim already uses. It's a backslash until you choose; Space is popular, since in Normal mode it only moves one character right. Set it first, let mapleader = " ", then map: nnoremap <leader>h :nohlsearch<CR> makes ␣ h put out the search highlights. Set the leader before the mappings that use it: a mapping reads the leader when it's made.
jk, switched on
This editor has inoremap jk <Esc> in its config. Each line needs a ; at the end: A, type ;, then j k instead of Esc. Then the next line.
Stuck? Show the keys
Type j and k one right after the other: Vim waits a moment after the j to see whether a k follows.This editor needs a keyboard. Read on, and play it at your computer.
In VS Code and JetBrains IDEs
The Vim plugins for other editors read their own config, so the same ideas travel in a different spelling.
- VS Code (VSCodeVim). Settings go in your user
settings.json. Some are the extension's, undervim.:"vim.hlsearch": true,"vim.leader": "<space>","vim.useSystemClipboard": true. Others are VS Code's own, because VS Code draws the screen:"editor.lineNumbers": "relative"for relative numbers,"editor.cursorSurroundingLines": 8for scrolloff,"editor.wordWrap"for wrapping.vim.ignorecaseandvim.smartcaseare already on. Mappings are lists ofbeforeandafterkeys, per mode. The extension can read a.vimrc(vim.vimrc.enable), but only its mappings, and it's marked experimental. - JetBrains IDEs (IdeaVim).
~/.ideavimrcreads like a.vimrc:set number relativenumber,set ignorecase smartcase,set scrolloff=8,inoremap jk <Esc>. It understands a subset of Vim's options, and adds its own for IDE actions. After an edit, IdeaVim offers a reload button in the editor, or type:source ~/.ideavimrc.
More on each: Vim in VS Code and Vim in JetBrains IDEs.
Start small
The fastest way to a config you hate is to copy someone's thousand lines on day one: plugins you didn't choose, mappings that move keys the tutorials assume, and no idea which line did what. Learn the stock editor first, then add options as you find a need.
- Start with nothing, or the few lines below. Use the editor for a week.
- Add a line when something bugs you twice. Try it with
:setfirst, then write it down. - One line, one reason. A comment above a line you might forget (
" keep 8 lines in view) is worth it. - Keep it in git. A dotfiles repo means a new laptop is one clone away, and every change has a date and a reason.
- Starting points worth reading, not pasting. Neovim 0.11 ships
$VIMRUNTIME/example_init.lua, a short, commented config::read $VIMRUNTIME/example_init.luaputs it in your file to read line by line.
A year from now your config will be a record of how you work, and every line in it will mean something to you. Practising the moves themselves is what the course is for.
Questions
- Where is my vimrc?
- Type
:echo $MYVIMRCinside Vim or Neovim: it prints the path of the config it loaded, or nothing if there isn't one. Vim looks for~/.vimrc(on Windows$HOME/_vimrc), Neovim for~/.config/nvim/init.luaorinit.vim. - Should I write init.lua or init.vim?
- Either works in Neovim, one at a time. Lua is what most Neovim plugins and their setup instructions use, so
init.luais the usual choice for a new config;init.vimis handy if you share lines with a Vim.vimrc. - Can Neovim use my existing .vimrc?
- Yes. Create
init.vimwithset runtimepath^=~/.vim runtimepath+=~/.vim/after,let &packpath = &runtimepathandsource ~/.vimrc, as Neovim's help (:help nvim-from-vim) suggests, and restart. - Why did syntax highlighting stop when I made a .vimrc?
- Without a
.vimrc, Vim loadsdefaults.vim, which turns on syntax highlighting and more. Your own file stops that. Addunlet! skip_defaults_vimandsource $VIMRUNTIME/defaults.vimat the top, orsyntax onandfiletype plugin indent on. - Should I start from a distribution like LazyVim?
- It gives you a full IDE at once, but also hundreds of choices you didn't make. You'll do better learning the stock editor and adding options as you need them; read a short example such as
$VIMRUNTIME/example_init.luainstead of pasting a big one.