Here’s the mental model most people start with: a buffer is an open file. You open a file, it appears in a buffer, you edit it, you save. Buffer equals file. Simple.
That model is wrong. Not subtly wrong — wrong in a way that makes half of Emacs confusing until you fix it.
A buffer is a region of memory. That’s it. Some buffers happen to be connected to files. Most of the interesting ones aren’t. The *scratch* buffer? Not a file. The *Messages* buffer? Not a file. The minibuffer at the bottom of your screen? Not a file. That *Help* window that popped up when you hit C-h f? Also not a file.
Once you stop thinking “buffer = file” and start thinking “buffer = named chunk of memory that Emacs can display and manipulate,” the whole system clicks.
What a buffer actually is
In Emacs, a buffer is a named, mutable region of text in memory. Every buffer has:
- A name (like
init.elor*Messages*) - A major mode (which determines how the text is edited —
org-mode,python-mode,fundamental-mode, etc.) - A point (your cursor position)
- A set of local variables (buffer-specific settings)
That’s the data structure. A buffer doesn’t need a file. It doesn’t need to be visible. You can have 200 buffers open and only see two of them. Buffers live in memory; windows are just viewports into them.
The distinction matters because Emacs does everything through buffers. Running a shell? That’s a buffer. Reading documentation? Buffer. Interacting with Git through Magit? Several buffers. Composing an email? Buffer. The buffer is the universal unit of “stuff you’re working with.”
File-visiting buffers
The most familiar type. You open a file with C-x C-f, Emacs reads the file contents into a new buffer, and the buffer tracks which file it came from. When you save with C-x C-s, the buffer contents get written back to disk.
The key detail: after the initial read, the buffer and the file are independent. If something else modifies the file on disk, your buffer doesn’t automatically update (unless you enable auto-revert-mode). The buffer is your working copy. The file is the persistent copy. They can diverge.
This is also why M-x revert-buffer exists — it re-reads the file from disk, replacing the buffer contents. It’s the “discard my changes and start over” command.
C-x C-f Open file into a new buffer
C-x C-s Save buffer contents back to its file
C-x C-w Save buffer to a different file (Save As)
Scratch buffer
When Emacs starts, it creates *scratch*. This buffer has no file. It’s a blank page in lisp-interaction-mode where you can type Elisp expressions and evaluate them with C-j.
Think of it as Emacs’s REPL. You can test ideas, run quick calculations, or just use it as a notepad. It’s called “scratch” because that’s what it is — scratch paper.
The thing people don’t realize: if you kill *scratch*, it’s gone. The contents vanish. There’s no file backing it, so there’s nothing to recover. Some configs auto-recreate it, but the contents are lost regardless.
I use *scratch* constantly — testing Elisp snippets, jotting down quick notes during debugging, drafting text I’ll paste somewhere else. It’s the lowest-friction writing surface in Emacs.
Messages buffer
*Messages* is Emacs’s log. Every message call in Elisp writes here. Warnings, confirmations, errors — they all flow into *Messages*. When you see a brief flash of text in the minibuffer that disappears before you can read it, it’s preserved in *Messages*.
Open it with C-h e (or M-x view-echo-area-messages). It’s read-only by default, which makes sense — it’s a log, not a scratch pad.
Why does this exist as a buffer instead of a log file? Because Emacs. Everything is a buffer. You can search it, copy from it, navigate it. If it were a file, you’d have to open it. Since it’s a buffer, it’s always there. The Emacs philosophy: if you might want to look at it, make it a buffer.
Special buffers
Any buffer whose name starts and ends with * is, by convention, a special buffer. These are generated by Emacs or its packages, not by you opening a file.
Some common ones:
| Buffer | What it does |
|---|---|
*scratch* |
Elisp scratch pad |
*Messages* |
Emacs log |
*Help* |
Documentation viewer |
*Completions* |
Shows completion candidates |
*Warnings* |
Compilation and runtime warnings |
*Backtrace* |
Elisp debugger output |
*Shell* |
Shell process |
*compilation* |
Output from M-x compile |
The *asterisk* convention is just a naming pattern, but Emacs respects it. Many commands (like C-x b with ido-mode) hide *-prefixed buffers from the default list because they’re “infrastructure” — you usually don’t switch to *Messages* the same way you switch between source files.
Special buffers are often read-only and have their own major modes. *Help* uses help-mode with its own keybindings for navigating cross-references. *compilation* uses compilation-mode with keybindings for jumping to error locations. Each one is a mini-application built on top of the buffer abstraction.
Read-only buffers
Any buffer can be toggled read-only with C-x C-q (read-only-mode). When a buffer is read-only, Emacs blocks edits and shows %% in the mode line instead of --.
Some buffers are born read-only: *Help*, *Messages*, *info*, and anything generated by a view-mode command. This isn’t a file permission thing — it’s a buffer property. The buffer variable buffer-read-only is either t or nil, and Emacs checks it before allowing modifications.
Why would you manually toggle read-only? Protection. If you have a reference file open that you definitely shouldn’t edit — a config from production, a generated file, someone else’s code you’re just reading — C-x C-q prevents accidental keystrokes from modifying it.
C-x C-q Toggle read-only mode
Indirect buffers
This is the one most people never learn about, and it’s genuinely powerful.
An indirect buffer shares the text of another buffer (the “base buffer”) but has its own:
- Point (cursor position)
- Narrowing (which portion of text is visible)
- Major mode
- Local variables
Same text. Independent views. If you edit the text in either buffer, both see the change — because it’s the same text in memory. But you can be looking at line 50 in one window and line 500 in another, with different modes, different narrowing, different everything-except-the-text.
Create one with M-x clone-indirect-buffer (bound to C-x 4 c).
Why this matters: narrowing
Narrowing restricts a buffer to show only a portion of its text. C-x n n narrows to the selected region, C-x n w widens back. When narrowed, Emacs behaves as if the rest of the buffer doesn’t exist — search, replace, and movement commands only operate within the narrowed region.
The problem with narrowing in a regular buffer: you can only have one narrowing at a time. If you want to focus on one function while referencing another function in the same file, you’re stuck.
Indirect buffers solve this. Clone the buffer, narrow each clone to a different section, and put them side by side. Same file, two focused views, simultaneously.
C-x 4 c Clone indirect buffer in another window
C-x n n Narrow to region
C-x n w Widen (remove narrowing)
The org-mode connection
If you use Org-mode, you’ve already used indirect buffers without knowing it. When you press C-c ' to edit a source block, Org creates an indirect buffer with the appropriate language mode. When you edit a subtree with org-tree-to-indirect-buffer, that’s an indirect buffer too. It’s the mechanism behind Org’s “focus on one section” workflow.
The minibuffer
That thin line at the very bottom of your Emacs frame? That’s a buffer too. The minibuffer is where Emacs prompts you for input — file names, command names, search strings, M-: expressions.
It’s special in several ways:
- It’s always present (you can’t kill it)
- It has its own window that’s normally one line tall
- It supports the same editing commands as any buffer (you can
C-a,C-e,C-k,M-bin the minibuffer) - It has its own history (accessible with
M-pandM-n)
The reason the minibuffer is a buffer and not “just an input prompt” is the same reason everything in Emacs is a buffer: uniformity. You already know how to navigate and edit text in a buffer. The minibuffer gives you those same skills at the input prompt. No separate modal input system to learn.
Buffer management
The practical stuff. How do you actually deal with all these buffers?
Switching
C-x b Switch to buffer (with completion)
C-x C-b List all buffers (opens *Buffer List*)
C-x b is the bread and butter. Type a buffer name (with tab completion), hit enter. With packages like ivy, vertico, or ido-mode, this becomes fuzzy-searchable and very fast.
Killing
C-x k Kill current buffer (prompts for confirmation if modified)
“Kill” means remove the buffer from memory. If it was visiting a file and had unsaved changes, Emacs asks before killing. If it’s *scratch* or a special buffer, it just vanishes.
ibuffer: the buffer manager
M-x ibuffer is the power tool. It shows all your buffers in a list with columns for name, size, mode, and file path. From there you can:
- Mark buffers with
m, then operate on all marked buffers - Kill marked buffers with
D - Save modified buffers with
S - Filter by mode, name, or filename with
/ - Sort by any column with
s - Group buffers by project, mode, or directory
It’s basically dired for buffers. If you have 50+ buffers open (and you will), ibuffer is how you stay sane.
M-x ibuffer Open buffer manager
m Mark buffer at point
D Kill marked buffers
S Save marked buffers
/ m Filter by major mode
/ n Filter by name
g Refresh list
Buffers vs. windows vs. frames
This trips people up, so let’s be explicit:
- Buffer — a named region of text in memory
- Window — a viewport showing a buffer (a split pane in your frame)
- Frame — what your OS calls a “window” (the actual GUI window)
One buffer can be displayed in zero, one, or many windows simultaneously. Splitting your frame with C-x 2 or C-x 3 creates a new window, not a new buffer. Both windows can even show the same buffer — scroll one, the other stays put.
Killing a window (C-x 0) doesn’t kill the buffer it was showing. The buffer is still in memory, just not visible. This is confusing if you expect “closing the pane” to close the file, but it’s consistent with the model: buffers and windows are independent things.
C-x 2 Split window horizontally (top/bottom)
C-x 3 Split window vertically (left/right)
C-x 0 Kill current window (buffer survives)
C-x 1 Kill all other windows (buffers survive)
C-x o Switch to next window
The mental model, summarized
Everything in Emacs is a buffer. Files get loaded into buffers. Help text gets rendered into buffers. Shell output goes into buffers. The minibuffer is a buffer. Even the buffer list is a buffer.
The types, at a glance:
| Type | File-backed? | Typical examples | Key trait |
|---|---|---|---|
| File-visiting | Yes | init.el, main.py |
Tracks a file on disk |
| Scratch | No | *scratch* |
Elisp REPL / notepad |
| Special | No | *Help*, *Messages*, *Shell* |
Generated by Emacs |
| Read-only | Either | *Help*, any toggled with C-x C-q |
Blocks modifications |
| Indirect | Shares base | Cloned buffers, Org edit buffers | Same text, independent view |
| Minibuffer | No | (the prompt line) | Always present, for input |
Once this clicks, you stop fighting the system. That *Backtrace* window that appeared? It’s just a buffer — search it, copy from it, kill it when you’re done. That Magit status view? A buffer with special keybindings. That weird *Async-native-compile-log* thing? A buffer logging native compilation. You already know how to interact with all of them.
The buffer is Emacs’s universal abstraction. Everything gets poured into it. And the payoff is that every skill you learn — navigation, search, editing, narrowing — works everywhere, because everywhere is a buffer.