What is the difference between :map and :noremap, and why should I use non-recursive mappings?
Answer
:nnoremap / :inoremap / :vnoremap
Explanation
Vim has two types of key mappings: recursive (:map, :nmap, :imap) and non-recursive (:noremap, :nnoremap, :inoremap). The critical difference is that recursive mappings expand other mappings within them, while non-recursive mappings use only default Vim behavior. Using non-recursive mappings prevents unexpected chains of remappings and is considered a best practice for almost all custom mappings.
How it works
:nmap j gjmapsjtogjin normal mode — but ifgjis also remapped, Vim follows that chain (recursive):nnoremap j gjmapsjtogjusing Vim's built-ingjbehavior, ignoring any other mappings ongj(non-recursive)- The
noreinnoremapstands for "non-recursive"
Recursive mappings can cause infinite loops. For example:
:nmap j k
:nmap k j
This creates an infinite loop — j triggers k, which triggers j, which triggers k... Vim will hang or error. With :nnoremap, each mapping refers to the original key behavior, so there is no loop.
Mode-specific non-recursive mappings
:nnoremap " Normal mode only
:inoremap " Insert mode only
:vnoremap " Visual and Select mode
:xnoremap " Visual mode only (not Select)
:cnoremap " Command-line mode only
:tnoremap " Terminal mode only
Example
Common safe mappings for your vimrc:
" Move by visual lines instead of physical lines
nnoremap j gj
nnoremap k gk
" Quick save
nnoremap <leader>w :w<CR>
" Clear search highlighting
nnoremap <leader>h :nohlsearch<CR>
" Better window navigation
nnoremap <C-h> <C-w>h
nnoremap <C-j> <C-w>j
nnoremap <C-k> <C-w>k
nnoremap <C-l> <C-w>l
" Escape insert mode with jk
inoremap jk <Esc>
Tips
- Always use
noremapvariants unless you specifically need recursive expansion (which is rare — typically only when chaining plugin mappings) - Use
:verbose nmap {key}to see where a mapping was defined and what it expands to — invaluable for debugging conflicts - Use
:nmapto list all normal mode mappings,:imapfor insert mode, etc. - Use
<leader>as a namespace prefix for your personal mappings to avoid colliding with built-in keys — set it withlet mapleader = " "(space is a popular choice) - Add
<silent>to suppress command-line echo:nnoremap <silent> <leader>w :w<CR> - Add
<buffer>for buffer-local mappings that only apply to the current file:nnoremap <buffer> <leader>r :!python3 %<CR> - Use
:unmap {key}or:nunmap {key}to remove a mapping