Doom Emacs common default keybindings
A categorized cheat sheet of commonly used Doom Emacs keybindings, written as a companion to my Neovim-to-Doom migration post. All sequences use the default SPC leader in evil mode unless noted otherwise.
Search
Doom splits what Telescope used to do as one tool across a few focused commands, mostly under the SPC s (“search”) prefix, backed by consult and vertico.
| Keybinding | Action |
|---|---|
SPC s s |
Search (fuzzy) inside the current buffer |
SPC s S |
Search current buffer, pre-filled with symbol at point |
SPC s b |
Search across all open buffers |
SPC s p |
Search (grep) across the whole project |
SPC s P |
Search across a different (non-current) project |
SPC * or SPC s * |
Search project for the symbol/word at point |
SPC s d |
Search a specific directory |
SPC s i |
Jump to a symbol (function, variable) in the current buffer (imenu) |
SPC s I |
Jump to a symbol across the whole project |
SPC s r |
Resume the last search session |
SPC / |
Shorthand alias for project-wide search |
SPC SPC |
Fuzzy find a file by name in the current project |
SPC . |
Fuzzy find a file relative to the current directory |
A few notes on regex vs. literal search: project search (SPC s p) is backed by ripgrep, which treats your query as a regex-capable pattern by default — no special mode-switch needed the way Telescope sometimes required. Inside the search minibuffer, you can keep typing to narrow results live, and C-n / C-p (or j / k if you’re in evil-collection’s minibuffer bindings) move between matches before you hit RET to jump.
Search and replace
Because evil mode emulates real vim, the classic :s substitute command works exactly like it did in Neovim — no new syntax to learn here, just a different set of tools for the project-wide case.
Single line (cursor’s current line only):
| Command | Action |
|---|---|
:s/old/new/ |
Replace the first match on the current line |
:s/old/new/g |
Replace all matches on the current line |
/old then cgn |
Jump to the next match of old and change it; repeat with . to step through remaining matches one at a time, reviewing each |
Whole buffer:
| Command | Action |
|---|---|
:%s/old/new/g |
Replace every match in the buffer |
:%s/old/new/gc |
Replace every match in the buffer, prompting y/n/a/q/l to confirm each one |
Visual-select lines, then : |
Auto-fills :'<,'>s/old/new/g, scoping the replace to just the selected region |
Evil’s :s uses vim-flavored regex syntax (\(...\) for groups, \d, \w, etc.), not native Emacs regex — so muscle memory from Neovim’s :%s transfers directly, which was one of the smoother parts of this whole switch.
Project-wide, where Doom departs from a single Telescope-style command and gives you two real options:
- Quick and blunt —
M-x projectile-replacefor a literal string replace across the whole project, orM-x projectile-replace-regexpfor a regex-based one. Projectile walks you through matches file by file with a confirmation prompt. No leader-key binding for this by default, so it’s worth binding one if you use it often. - Visual and reviewable — run
SPC s pto ripgrep the project, export the results into a real, editable buffer (viaembark-export, typically onC-c C-efrom the search results — exact key can vary by Doom version, check withSPC h kif it doesn’t fire), then flip that results buffer intowgrep-mode(C-c C-p). At that point it behaves like any other buffer: run:%s/old/new/gacross it, eyeball the diff-style view, thenC-c C-eto write the changes back out to every affected file, orC-c C-kto bail out without touching anything.
I lean on option 2 for anything risky — being able to see every change across every file before committing to it is a step up from a blind project-wide replace.
Windows
Window management borrows from vim’s C-w prefix but also has a full SPC w leader-based equivalent, which is what I default to.
| Keybinding | Action |
|---|---|
SPC w v |
Split window vertically (side by side) |
SPC w s |
Split window horizontally (stacked) |
SPC w c or SPC w d |
Close the current window |
SPC w o |
Close all other windows (keep only the current one) |
SPC w m |
Toggle maximize on the current window (zoom in/out) |
SPC w w |
Cycle focus to the next window |
SPC w h/j/k/l |
Move focus left / down / up / right |
SPC w H/J/K/L |
Move the window itself (swap position) left / down / up / right |
SPC w = |
Balance all windows to equal size |
SPC w r |
Rotate windows forward |
SPC w R |
Rotate windows backward |
SPC w u |
Undo the last window layout change |
SPC w U |
Redo a window layout change |
SPC 1–SPC 9 |
Jump directly to window number N |
The vim-native C-w versions (C-w v, C-w s, C-w c, C-w =, C-w o) still work if that’s what your fingers already know — Doom doesn’t take those away.
Git
Doom’s git interface is Magit, which is one of the bigger quality-of-life upgrades coming from a terminal-git-plus-fugitive workflow. Rather than a thin keybinding wrapper, Magit gives you a full interactive status buffer: you stage and unstage individual hunks or even individual lines, write commit messages in a dedicated buffer with syntax highlighting, and see diffs inline without leaving the window. It’s discoverable — pressing ? almost anywhere in Magit shows you every available action in that context, which made it easy to pick up without memorizing everything up front.
The general workflow I use daily: open the status buffer, stage the hunks I want with s, commit with c c, and push with P p. Everything happens without touching a separate terminal.
| Keybinding | Action |
|---|---|
SPC g g |
Open Magit status (the main git dashboard) |
SPC g b |
Show git blame for the current line/region |
SPC g B |
Open the current line/file on the remote (GitHub, etc.) in your browser |
SPC g L |
Open the Magit log for the current buffer/project |
SPC g f |
Find/open a file as it exists in a git revision |
SPC g t |
Open git-timemachine to step through a file’s history |
SPC g C |
Clone a repository |
SPC g F |
Fetch from remote |
Inside the Magit status buffer itself (not leader-key bindings, just single keys):
| Key | Action |
|---|---|
s |
Stage the hunk/file at point |
u |
Unstage the hunk/file at point |
c c |
Start a commit |
P p |
Push to the current branch’s upstream |
F p |
Pull from upstream |
b b |
Checkout a branch |
RET |
Visit the thing at point (file, commit, hunk) |
g r |
Refresh the status buffer |
q |
Quit back out of Magit |
Terminal
| Keybinding | Action |
|---|---|
SPC o t |
Toggle a popup terminal (vterm) at the project root |
SPC o T |
Open a dedicated (non-popup) terminal buffer |
vterm behaves a bit differently than a typical Emacs buffer: while you’re in insert state, most keystrokes pass straight through to the underlying shell, since it’s a real terminal emulation rather than a text buffer. Drop into evil’s normal state (ESC) to scroll back, visually select, or yank terminal output the way you would in a normal buffer.
Buffers & Files
| Keybinding | Action |
|---|---|
SPC b b |
Switch to another open buffer |
SPC b d |
Kill (close) the current buffer |
SPC b n |
Go to the next buffer |
SPC b p |
Go to the previous buffer |
] b |
Next buffer (Doom’s “bracket” navigation convention) |
[ b |
Previous buffer |
SPC f f |
Find/open a file |
SPC f s |
Save the current file |
SPC f r |
Open a recently-opened file |
SPC f y |
Copy the current file’s path to the clipboard |
Doom’s bracket convention ([ x / ] x) shows up in a few other places too — ] e / [ e for next/previous error, ] t / [ t for tabs, and so on. Once you notice the pattern it applies more broadly than it first appears.
Code Navigation & LSP
| Keybinding | Action |
|---|---|
SPC c d |
Jump to definition |
SPC c D |
Jump to references |
SPC c r |
Rename symbol |
SPC c a |
Show code actions |
SPC c f |
Format the buffer/region |
K |
Show documentation/hover info for symbol at point |
SPC h k |
Describe a keybinding (what does this key actually do?) |
Optional but commonly used plugins
Doom ships with a lot enabled out of the box (projectile, which-key, company, doom-modeline), but these are worth knowing about since they come up often in the Doom ecosystem and are easy to enable via module flags in ~/.doom.d/init.el or as extra packages in ~/.doom.d/packages.el:
- treemacs — a file-tree sidebar, similar to nvim-tree or neo-tree. Toggle with
SPC o p. - org-roam — networked note-taking/zettelkasten built on top of org-mode, popular for personal knowledge management.
- magit-todos — surfaces
TODO/FIXMEcomments from your codebase inside Magit’s status buffer. - corfu — a lighter-weight alternative to the default
companycompletion frontend, if you want something closer to a minimal popup. - flycheck (or flymake on newer configs) — inline linting/diagnostics, usually pulled in automatically by language modules.
- apheleia or format-all — auto-formatting on save, handy if you’re used to
conform.nvimor similar. - centaur-tabs — adds a visible tab bar across the top of the frame, if you miss bufferline-style tabs from Neovim.
After enabling any module or package, run doom sync and restart Emacs for it to take effect — that deliberate step is exactly the thing I appreciated after fighting silent breakage in Neovim.