Dev In The Mountain Header
A Developer In The mountains having fun

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 abd SPC f ("find"). Think of search for like a semi-manual search (i want to look inside dir called x for x). and as find as i don't know where x is and i want to find it.

KeybindingAction
SPC s sSearch (fuzzy) inside the current buffer
SPC s SSearch current buffer, pre-filled with symbol at point
SPC s bSearch across all open buffers
SPC s pSearch (grep) across the whole project
SPC s PSearch across a different (non-current) project
SPC * or SPC s *Search project for the symbol/word at point
SPC s dSearch a specific directory
SPC s iJump to a symbol (function, variable) in the current buffer (imenu)
SPC s IJump to a symbol across the whole project
SPC s rResume the last search session
SPC /Shorthand alias for project-wide search
SPC SPCFuzzy 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):

CommandAction
:s/old/new/Replace the first match on the current line
:s/old/new/gReplace all matches on the current line
/old then cgnJump to the next match of old and change it; repeat with . to step through remaining matches one at a time, reviewing each

Whole buffer:

CommandAction
:%s/old/new/gReplace every match in the buffer
:%s/old/new/gcReplace 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:

  1. Quick and blunt — M-x projectile-replace for a literal string replace across the whole project, or M-x projectile-replace-regexp for 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.
  2. Visual and reviewable — run SPC s p to ripgrep the project, export the results into a real, editable buffer (via embark-export, typically on C-c C-e from the search results — exact key can vary by Doom version, check with SPC h k if it doesn't fire), then flip that results buffer into wgrep-mode (C-c C-p). At that point it behaves like any other buffer: run :%s/old/new/g across it, eyeball the diff-style view, then C-c C-e to write the changes back out to every affected file, or C-c C-k to 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.

KeybindingAction
SPC w vSplit window vertically (side by side)
SPC w sSplit window horizontally (stacked)
SPC w c or SPC w dClose the current window
SPC w oClose all other windows (keep only the current one)
SPC w mToggle maximize on the current window (zoom in/out)
SPC w wCycle focus to the next window
SPC w h/j/k/lMove focus left / down / up / right
SPC w H/J/K/LMove the window itself (swap position) left / down / up / right
SPC w =Balance all windows to equal size
SPC w rRotate windows forward
SPC w RRotate windows backward
SPC w uUndo the last window layout change
SPC w URedo a window layout change
SPC 1–SPC 9Jump 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.

KeybindingAction
SPC g gOpen Magit status (the main git dashboard)
SPC g bShow git blame for the current line/region
SPC g BOpen the current line/file on the remote (GitHub, etc.) in your browser
SPC g LOpen the Magit log for the current buffer/project
SPC g fFind/open a file as it exists in a git revision
SPC g tOpen git-timemachine to step through a file's history
SPC g CClone a repository
SPC g FFetch from remote

Inside the Magit status buffer itself (not leader-key bindings, just single keys):

KeyAction
sStage the hunk/file at point
uUnstage the hunk/file at point
c cStart a commit
P pPush to the current branch's upstream
F pPull from upstream
b bCheckout a branch
RETVisit the thing at point (file, commit, hunk)
g rRefresh the status buffer
qQuit back out of Magit
'd w'diff compare: working tree to HEAD
'd r'diff compare: range compare

Notes

  • To get the diff of only the current file in magit use M-x magit-diff-buffer-file

Terminal

KeybindingAction
SPC o tToggle a popup terminal (vterm) at the project root
SPC o TOpen 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

KeybindingAction
SPC b bSwitch to another open buffer
Ctl 6Switch to the latest buffer
SPC b dKill (close) the current buffer
SPC b nGo to the next buffer
SPC b pGo to the previous buffer
] bNext buffer (Doom's "bracket" navigation convention)
[ bPrevious buffer
SPC f fFind/open a file
SPC f sSave the current file
SPC f rOpen a recently-opened file
SPC f yCopy 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

KeybindingAction
SPC c dJump to definition
SPC c DJump to references
g dJump to definiition
g DJump to references
SPC c rRename symbol
SPC c aShow code actions
SPC c fFormat the buffer/region
KShow documentation/hover info for symbol at point
SPC h kDescribe a keybinding (what does this key actually do?)

Workspaces

KeybindingAction
SPC TAB TABopen workspaces bar
SPC TAB 1open workspaces number 1

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/FIXME comments from your codebase inside Magit's status buffer.
  • corfu — a lighter-weight alternative to the default company completion 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.nvim or 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.

More places to find me
Mental Health
follow me on Mastodon