Skip to main content
Neovim’s diff mode allows you to view and merge differences between two to eight files simultaneously, making it an excellent tool for code reviews and conflict resolution.

Starting Diff Mode

From the Command Line

nvim -d file1.txt file2.txt
By default, diff mode uses vertical splits. Add -o for horizontal splits, or set set diffopt+=horizontal in your config.

From Within Neovim

:diffsplit file.txt         " Open file.txt in diff mode
:vert diffsplit file.txt    " Vertical split (default)
:diffthis                   " Make current window part of diff
:diffpatch patch.diff       " Apply patch and show diff

Diff Window Options

When diff mode starts, these options are automatically set:
'diff'          = on        " Enable diff mode
'scrollbind'    = on        " Sync scrolling
'cursorbind'    = on        " Sync cursor position
'foldmethod'    = diff      " Fold unchanged lines
'foldcolumn'    = 2         " Show fold column
'wrap'          = off       " Disable line wrapping
'scrollopt'     += hor      " Horizontal scrolling

Jump Between Changes

]c          " Jump to next change
[c          " Jump to previous change
[c          " With count: 3]c jumps to 3rd next change
These commands work like ]s and [s for spell checking.

Merging Changes

Obtain and Put Changes

do              " Obtain diff from other window
:diffget        " Same as 'do'
:diffget 2      " Get from buffer number 2
:diffget //2    " Get from window 2 (3-way merge)
do stands for “diff obtain” (not “diff open”) because dg would conflict with dgg.

Range Operations

:5,10diffget        " Obtain lines 5-10 from other window
:20,30diffput       " Put lines 20-30 to other window
:0,$+1diffget       " Get all differences

Diff Highlighting

Differences are highlighted with these groups:
GroupDescription
DiffAddLines added (only in this buffer)
DiffChangeLines changed
DiffTextExact changed text within a line
DiffDeleteLines deleted (filler lines)
DiffTextAddAdded text (when inline: is not “simple”)

Customize Diff Colors

" For light backgrounds
highlight DiffAdd    guibg=#d0ffd0 guifg=NONE
highlight DiffChange guibg=#ffffcc guifg=NONE
highlight DiffDelete guibg=#ffcccc guifg=NONE
highlight DiffText   guibg=#ffff80 guifg=NONE

" For dark backgrounds
highlight DiffAdd    guibg=#1a3a1a guifg=NONE
highlight DiffChange guibg=#3a3a1a guifg=NONE
highlight DiffDelete guibg=#3a1a1a guifg=NONE
highlight DiffText   guibg=#4a4a1a guifg=NONE

Diff Options

Configure Diff Behavior

:set diffopt=filler,context:3       " Show 3 lines of context
:set diffopt+=iwhite                " Ignore whitespace
:set diffopt+=algorithm:patience    " Use patience diff algorithm
:set diffopt+=indent-heuristic      " Better indentation alignment
:set diffopt+=vertical              " Always use vertical splits
Common diffopt flags:
FlagEffect
fillerShow filler lines for deleted lines
context:NShow N lines of context
iwhiteIgnore whitespace changes
icaseIgnore case changes
iblankIgnore blank lines
horizontalUse horizontal splits
verticalUse vertical splits
followwrapFollow ‘wrap’ setting
indent-heuristicBetter diff output

Inline Diff Options

:set diffopt+=inline:simple     " Highlight changed regions simply
:set diffopt+=inline:char       " Highlight character differences
:set diffopt+=inline:word       " Highlight word differences
:set diffopt+=inline:none       " Don't highlight inline changes

Managing Diff Windows

Update Diffs

:diffupdate         " Recalculate differences
:diffupdate!        " Recalculate and check for external changes
Neovim tries to keep diffs updated automatically, but complex changes may require manual :diffupdate.

Exit Diff Mode

:diffoff            " Turn off diff mode in current window
:diffoff!           " Turn off diff in all windows
:set nodiff         " Alternative for current window

Practical Diff Workflows

Compare File with Saved Version

Create a command to diff the current buffer with the file on disk:
command! DiffOrig vert new | set buftype=nofile | read ++edit # | 0d_
  \ | diffthis | wincmd p | diffthis

" Usage:
:DiffOrig
1

Make changes to a file

Edit your file without saving.
2

Compare with saved version

:DiffOrig
3

Navigate and merge

Use ]c and [c to jump between changes, do and dp to merge.
4

Exit diff mode

:diffoff!

Three-Way Merge

For merge conflicts:
nvim -d base.txt mine.txt theirs.txt
" In 'mine.txt' window
:diffget //2        " Get from theirs (if needed)
:diffput //1        " Put to base

Advanced Diff Features

Diff Anchors

Force diff alignment at specific lines:
" Set marks in both files at corresponding lines
:set diffanchors='a

" Or use patterns
:set diffanchors=1/^function\ main(

" Enable anchor mode
:set diffopt+=anchor
Diff anchors help when functions or blocks have moved between files.

Custom Diff Expression

Use a custom diff program:
set diffexpr=MyDiff()

function! MyDiff()
  let opt = ""
  if &diffopt =~ "icase"
    let opt = opt .. "-i "
  endif
  if &diffopt =~ "iwhite"
    let opt = opt .. "-b "
  endif
  silent execute "!diff -a --binary " .. opt .. v:fname_in .. " " 
    \ .. v:fname_new .. " > " .. v:fname_out
  redraw!
endfunction

Patch Files

Apply and view patches:
:diffpatch changes.patch    " Apply patch and show diff
Custom patch expression:
set patchexpr=MyPatch()

function! MyPatch()
  call system("patch -o " .. v:fname_out .. " " 
    \ .. v:fname_in .. " < " .. v:fname_diff)
endfunction

Diff Folding

Unchanged lines are automatically folded:
zo          " Open fold to see context
zc          " Close fold
zr          " Reduce folding (more context)
zm          " More folding (less context)

Configure Diff Context

:set diffopt=context:5      " Show 5 lines of context
:set diffopt=context:0      " Show only changes
:set diffopt=context:999    " Show entire file

Example Configurations

Git Merge Tool

Configure Neovim as your Git merge tool:
# In ~/.gitconfig
[merge]
    tool = nvim
[mergetool "nvim"]
    cmd = nvim -d $LOCAL $MERGED $REMOTE
    trustExitCode = true
[mergetool]
    keepBackup = false

Diff Keybindings

" Quick diff commands
nnoremap <leader>dt :diffthis<CR>
nnoremap <leader>do :diffoff<CR>
nnoremap <leader>du :diffupdate<CR>
nnoremap <leader>dg :diffget<CR>
nnoremap <leader>dp :diffput<CR>

" Navigate diffs
nnoremap <leader>dn ]c
nnoremap <leader>dN [c

" Quick 3-way merge
nnoremap <leader>d1 :diffget //2<CR>
nnoremap <leader>d2 :diffget //3<CR>

Auto-save After Diff Obtain

" Automatically save after getting changes
autocmd BufWritePost * if &diff | diffupdate | endif

Troubleshooting

Diff Not Updating

:diffupdate         " Force recalculation
:set diffopt+=algorithm:histogram  " Try different algorithm

Alignment Issues

:set nodiff | set diff      " Reset diff mode
:windo diffoff | windo diffthis    " Restart diff in all windows

Slow Diff Performance

:set diffopt-=indent-heuristic      " Disable heuristic
:set diffopt=filler,context:1       " Reduce context
:set diffexpr=                      " Use internal diff (faster)
For large files, consider reducing context or using the internal diff library (leave diffexpr empty).

Build docs developers (and LLMs) love