Registers In Depth
Vim Intermediate/Advanced
Chapter 2 — Registers In Depth
What Registers Are For
Every editor has a clipboard — but most editors give you exactly one. Copy something new, and whatever was there before is gone. Vim's answer is registers: up to dozens of independent storage slots, each holding its own piece of yanked or deleted text, all available simultaneously.
This matters more than it sounds. Imagine restructuring a function: you need to move three separate blocks of code to three different places. In a single-clipboard editor, you'd yank the first block, paste it, then have to go back and re-select the second block from scratch — because copying it would have overwritten the first. With registers, you can yank all three blocks into three named slots up front, then paste each one exactly where it belongs, in any order.
Chapter 1's macros are themselves stored in a register — this chapter is what makes that fact make sense, and unlocks a much wider set of copy/paste workflows along the way.
The Unnamed Register
Every plain y (yank) or d/c (delete/change) you've used since Chapter 1 of Learning Vim already uses a register — you just haven't had to name it. This default is the unnamed register, written "":
yy # yanks the current line into the unnamed register dd # deletes the current line into the unnamed register (overwriting whatever was yanked) p # pastes from the unnamed register
yy, then delete a different line with dd before pasting — the delete silently replaced what you yanked. p now pastes the deleted line, not the one you originally copied. Named and numbered registers, below, exist largely to avoid this exact trap.
Named Registers a–z and A–Z
Prefixing any yank, delete, or paste with "{letter} targets a specific named register instead of the unnamed one:
"ayy # yank the current line into register 'a' "bdd # delete the current line into register 'b' "ap # paste from register 'a'
The distinction between lowercase and uppercase is deliberate and useful:
| Form | Behavior |
|---|---|
"a (lowercase) | Overwrites register a — whatever was there before is discarded |
"A (uppercase) | Appends to register a — adds to whatever's already there, instead of replacing it |
# Collect three scattered lines into ONE register, in order: "ayy # yank line 1 into 'a' (overwrites) "Ayy # yank line 2, APPENDED to 'a' "Ayy # yank line 3, APPENDED to 'a' # register 'a' now holds all three lines, in the order collected "ap # paste all three at once
"A, then paste the whole assembled block in one place. This is a genuinely different capability from a normal clipboard, not just a naming convenience.
Viewing register contents
:registers # list every register and a preview of its contents :reg # shorthand for the same command :reg a b # list only registers 'a' and 'b'
--- Registers ---
"" function processOrder(id) {
"0 const result = calculate(x, y)
"a const BASE_URL = "https://api.example.com"^Jconst TIMEOUT = 5000
"1 old line that was deleted
The ^J you'll sometimes see inside a register's preview represents a newline character — visible proof that register a above holds two full lines appended together, not one.
Numbered Registers 0–9
Vim automatically maintains ten numbered registers without you ever naming them explicitly — but they follow two different rules depending on the number.
"0 — the yank register
Holds the text from your most recent yank specifically (y, yy) — and only a yank. A subsequent delete does not touch "0, which is exactly what makes it useful: "0p reliably pastes "the last thing I actually copied," even after several unrelated deletes.
"1 – "9 — the delete ring
Holds a rolling history of your last nine deletions. Each new delete pushes into "1, shifting the previous "1 down to "2, "2 to "3, and so on — "9 falls off the end entirely. "1p pastes your most recent delete; "2p the one before that.
# Demonstrating the split between "0 and the "1-"9 ring: yy # yank line A — now in both "" and "0 dd # delete line B — "" now holds B, "1 holds B, but "0 STILL holds A "0p # pastes line A — the yank register was untouched by the delete "1p # pastes line B — the most recent delete
"0 would be useless for anything but the very next keystroke. Separating "things I deleted" from "the thing I deliberately copied" is what makes "0p dependable.
Special Registers
A handful of registers are always populated automatically, each recording something specific about your session:
| Register | Holds |
|---|---|
"% | The current file's name |
": | The most recently executed Ex command (anything typed after :) |
"/ | The most recent search pattern |
". | The last text that was inserted, in Insert mode |
"= | The expression register — evaluates a Vim expression and inserts the result |
"* | The system clipboard (selection-based, platform dependent) |
"+ | The system clipboard (the one Ctrl+C/Ctrl+V in other apps actually uses, on most Linux setups) |
# Insert the current filename into the text itself: i (enter Insert mode) Ctrl-r % # pastes the "% register — the filename — right into the text # Use "+ to copy INTO the OS clipboard, so it's pasteable in another app: "+yy # yank the current line to the system clipboard # The expression register does math (or any Vim expression) inline: i (enter Insert mode) Ctrl-r =12*8<CR> # inserts "96" directly into the text
Ctrl-r works from Insert mode and the command line alike. Any register — named, numbered, or special — can be pasted with Ctrl-r {register} while typing, without leaving Insert mode to paste and re-enter it. This is the register system's answer to "I need to paste something while I'm already typing."
"* vs "+ genuinely differs by platform and setup. On many Linux systems, "* reflects the "primary selection" (whatever's currently highlighted, pasted with a middle-click) while "+ is the clipboard proper (Ctrl+C/Ctrl+V). On Windows and macOS builds of Vim, the two are often aliased to the same clipboard. If a clipboard yank doesn't paste where you expect in another application, try the other one before assuming clipboard integration is broken.
Practical Workflow: Juggling Multiple Registers
A realistic scenario: refactoring a function's three parameters into a config object, each needing to move to a different destination.
Workflow — moving three separate values to three separate destinations
iw) into register a.
b.
c. All three are now held independently — none overwrote another.
a.
Compare this to a single-clipboard workflow, which would require interleaving every yank with its paste — copy one, immediately paste it, go back for the next — because a second copy would destroy the first. Named registers remove that ordering constraint entirely.
Commands Introduced in This Chapter
Chapter 2 — Command Reference
:reg a b)