Insert Mode Mastery
Most beginners only know i to enter Insert mode. In reality, there are 10+ entry points, each placing the cursor at a different position. Choosing the right entry point eliminates unnecessary navigation.
The goal is to enter Insert mode exactly where you need to start typing — not to enter Insert and then navigate.
Insert Mode Entry Points
| Key | Where you start typing |
|---|---|
| i | Before cursor |
| a | After cursor (append) |
| I | Start of line (first non-blank) |
| A | End of line |
| o | New line below cursor |
| O | New line above cursor |
| s | Substitute: delete char, enter insert |
| S | Substitute: delete line, enter insert |
| c{motion} | Change: delete motion, enter insert |
| C | Change to end of line |
| gi | Return to last insert position |
Read the ruler — the ^ marks where the cursor sits when Insert mode begins:
hello world
^ ^
bi ea
bi→ back to the start of the word, insert before it.ea→ to the end of the word, append after it.
getData(userId)
^
f(a
f(a→ find(, then append after it.
oldVariable = 1
^^^^^^^^^^^
ciw
ciw→ change the whole inner word, no matter where the cursor is inside it.
Choosing the Right Entry Point
Scenario: Add a semicolon at end of line
❌ Wrong: hjklA;Esc (navigated manually)
✅ Right: A;Esc (jump to end, append)
Scenario: Add text after a word
❌ Wrong: wia (word jump, insert, then position)
✅ Right: ea (end of word, append)
Scenario: Add text before a word
❌ Wrong: biw (back, insert, word jump — unnecessary)
✅ Right: bi (back to word start, insert before it)
Scenario: Replace a whole line
❌ Wrong: 0d$i (start, delete to end, insert)
✅ Right: S (substitute line, enter insert)
Editing Inside Insert Mode
You can do light editing without leaving Insert mode:
| Key | Action |
|---|---|
| Backspace | Delete previous character |
| Ctrl+h | Delete previous character (same as Backspace) |
| Ctrl+w | Delete previous word |
| Ctrl+u | Delete to beginning of line |
| Ctrl+j or Enter | New line |
| Ctrl+t | Indent (add shiftwidth spaces) |
| Ctrl+d | De-indent (remove shiftwidth spaces) |
The Ctrl+o Trick — One Normal Command
Ctrl+o executes exactly one Normal mode command and returns to Insert mode.
In Insert mode:
Ctrl+o $ → jump to end of line, stay in Insert
Ctrl+o dd → delete line, return to Insert
Ctrl+o 0 → jump to line start, stay in Insert
Ctrl+o zz → center screen, return to Insert
This is invaluable for quick corrections without fully exiting Insert mode.
Inserting Special Characters and Registers
Ctrl+r {register} → Insert contents of register
Ctrl+r " → Insert from unnamed (default) register
Ctrl+r + → Insert from system clipboard
Ctrl+r 0 → Insert from yank register
Ctrl+r a → Insert from named register 'a'
Ctrl+r = → Insert result of expression (e.g., 2+2 → 4)
Using the Expression Register
Ctrl+r = 7 * 8 Enter → Inserts 56
Ctrl+r = system('date') Enter → Inserts current date
Digraphs — Typing Special Characters
Insert special Unicode characters without leaving Insert mode:
Ctrl+k {char1} {char2} → Type a digraph
Examples:
Ctrl+k : e → ë (e umlaut)
Ctrl+k ' e → é (e acute)
Ctrl+k >> a → ⬇ (varies by config)
See all digraphs: :digraphs
Autocompletion in Insert Mode
Neovim has built-in completion before any plugins:
| Key | Completion source |
|---|---|
| Ctrl+n | Keyword completion (forward) |
| Ctrl+p | Keyword completion (backward) |
| Ctrl+x Ctrl+f | Filename completion |
| Ctrl+x Ctrl+l | Whole-line completion |
| Ctrl+x Ctrl+] | Tag file completion |
| Ctrl+x Ctrl+o | Omni-completion (language-aware) |
With nvim-cmp (covered in Module 8), this is replaced with a much better completion system. But the built-in completions always work, even without plugins.
Smart Insert Entry Patterns
Pattern 1: Append After Matching Char
For: let result = calculate(value
Goal: close the parenthesis
f(a) → find '(', append after one char → )
or:
A) → jump end of line, append ) (if ) belongs at end)
Pattern 2: Insert Before a Specific Word
For: let result = calculate(value)
Goal: add `const` before `result`
b i const Esc → back to word start, insert before it
The counterpart to ea (end of word, append). Use b to reach the word start regardless of cursor position on the line.
Pattern 3: Change a Word in the Middle
For: const oldVariable = getData()
Goal: rename oldVariable to newName
ciw newName → change inner word under cursor → type replacement
* ciw newName → if cursor is elsewhere, find the word first
Pattern 4: Create a Function Body
For: function myFunc() {}
Goal: add body inside braces
f{a → find '{', append after
Enter → new line (auto-indented)
...code...
Esc → done
Practice
Open the step-by-step drills: practice-folder/nvim/02-modal-editing/insert-practice.md
(also available via the shell alias n02-insert).
| Drill | What it trains | Steps |
|---|---|---|
i | Insert before the cursor | Cursor on the p of apple → i → type XX + Esc → aXXpple |
I | Insert at first non-blank | Cursor anywhere on cherry → I → type ZZ + Esc |
a / A | Append after cursor / line end | On hello world → a after h; A after world |
o / O | Open line below / above | On line one → o → type → Esc; O opens above |
s / S | Delete char / line, then Insert | On abcdefghij → s → X → Esc; S on a whole line |
c{motion} / C | Change motion / to end of line | cw, ciw, c$/C, c0, cc on the fox/jug lines |
Ctrl+o | One Normal cmd from Insert | A → Ctrl+o j → keep typing; try Ctrl+o dd, Ctrl+o o |
| Quick fire | Entry-point recap | i, a, I, A, o, O on one line, undoing between each |
In LazyVim
Insert mode mastery is identical in LazyVim. Standard shortcuts like <C-w> (delete word) or <C-u> (delete line) work as expected.
LazyVim also pre-configures snippet expansion and auto-completion via blink.cmp (or nvim-cmp in older setups) to speed up Insert mode typing.
| Aspect | Vanilla Neovim | LazyVim |
|---|---|---|
| Insert Mode Entry | i, I, a, A, o, O | Same |
| Auto-completion | Built-in omnifunc or manual setup | blink.cmp pre-configured |