Doom Emacs Documentation

A compilation of resources for Doom Emacs users

Our documentation was designed to be read within Doom Emacs (accessible with M-x doom/help) or online at If viewed anywhere else (e.g. Github), there is no guarantee most links will work.

1. Introduction

You’ve made it to the Doom Emacs manual. You’ve probably realized the cold hard truth by now: Emacs is hard™. Sure, Doom makes things easier, but it can’t totally flatten that learning curve – and it also adds one of its own.

To help you along, I’ve laid out our best learning resources for using, abusing, and confusing Doom Emacs, and plenty of guidance to get you where you’re going. If at any time you want to know the formatting or conventions of the documentation you’re reading, visit our help page. There’s a link to it at the top right of every page.

Users reading our documentation inside Emacs should check out our mini tutorial.

That said, I know this is a lot to take in. If deciding where to go next is proving difficult, here are a couple suggestions:

1.1. Frequently asked questions

A lot of questions get tossed at our doors. Questions about using, configuring, extending, sponsoring, or contributing to the project – and then some. The most common ones are added to our FAQ.

  • Project – Questions about the project and its author
  • How do I… – Common questions about Doom’s use and configuration
  • Common issues – Common problems and how to fix them
  • Community – About our Discourse, Discord or Github
  • Contributors – About github, PRs, issues, and contributing
  • Sponsors – For sponsors and sponsors to-be

Have a question of your own? Post them on Discourse or Discord.

1.2. Following project development

Doom Emacs has been in active development since the project began in 2014. These resources were created to help you track its progress, the state of the author, and his vision for it:

1.3. Where else to find help

Doom Emacs has a large, active, and friendly community across several platforms. You don’t have to use Doom (or Emacs) to be on them, but they are treated as an extension of our documentation. If our built-in docs don’t cover something, folks will likely direct you to one of these, either to find an existing answer or to present the question to the community at large:


This is our official nexus for discussion, support, and announcements. It also seconds as our community wiki; where we keep guides, tutorials, cheat sheets, and more. There is no better place for users to track the state of the project or ask for help.

Popular resources:

  • Official guides & tutorials
  • 3rd-party resources
  • Example user configurations
  • Cheat sheets
  • Community FAQs (commonly raised issues and questions)
  • Discourse FAQ
  • Helpful guides
  • Common configuration mistakes
Our Discord is a less formal environment for talking shop, being social, or engaging with @hlissner (Doom’s maintainer). Come say hi!
The twitter feed is an alternative channel for announcements. If you don’t twitter, you’re better off subbing to the Announcements section of our Discourse.

Our matrix space is available as an (open source) alternative to Discord. It is bridged to our Discord server and serves the same purpose.

This isn’t available yet, and won’t be until the Matrix ecosystem has finalized support for Spaces.

Please don’t contact Henrik or moderators directly (by email or DM) for assistance with [Doom] Emacs. Present your issue to the community on Discourse or Discord instead, to avoid inundating them and to give others a chance to chime in.

1.3.1. TODO The Emacs community

If your issue isn’t particular to Doom, you’ll have better luck asking the larger Emacs community instead:

2. TODO Release Notes

Our release notes are a work in progress.

3. User manual

Our 0-to-100 guide for setting up, maintaining, and troubleshooting Doom Emacs. All the absolute essentials that Doom users ought to know, all in one place, including a soft introduction to Emacs concepts that may be alien to beginners, especially those coming from another editor.

  • Introduction – An intro the project, its goals and author.
  • Quick start – A TL;DR crash course for beginners with busy lives
  • Install – Installing Emacs, its dependencies, and Doom
  • Update – Keep Doom up-to-date (or roll back)
  • Concepts – A glossary for essential concepts and terms
  • Environment – Set up your environment so Doom can find your programs
  • Configure – Configuring Doom, binding keys, and managing plugins
  • Troubleshoot – Strategies for debugging problems and issues

3.1. TODO Introduction

So what is Doom Emacs? It’s a configuration framework for GNU Emacs tailored for experienced Emacs users, who want:

  • An Emacs Lisp framework that doesn’t abstract Emacs away,
  • A reproducible, shell-scriptable package manager with disaster recovery built-in,
  • The performance of a hand-rolled config or better,
  • And batteries included, but only where you want them to be.
  • A framework or a starter kit (what’s the difference?)

It can be a foundation for your own config (with as many – or as few – batteries included as you like), a reference for enthusiasts building their own, or anywhere in between.

Why was Doom written? Picture this. The year is 2014. A spry, shell-dwelling, and melodramatic hellspawn from the frigid North lays his tired eye on his old friend of 12 years – Vim – and for the last time. He is exhausted. He would not wish VimScript on even the Doom slayer himself, but like any good agent of evil he wants more power; he wants a better Vim than Vim.

So he visits every contemporary editor you can name, but their Vim plugins disappoint him to the point of desperation.

Henrik Lissner, a Canadian/Danish devops engineer and gamedev hobbyist. After 12 years as an avid Vim user (and a brief stint with every contemporary editor you can name), he discovered Emacs, then Evil, and was convinced he’d found a better Vim than Vim. Though, the Vim plugins of said contemporary text editors had likely disappointed him to the point of desperation, and he’d already begun wondering where his life had gone so, so wrong.

Still, in a perilous effort to learn Emacs and Emacs Lisp, he tinkered away. The year is 2014, and that config would later become Doom Emacs.

3.1.1. TODO Why Emacs?

With the likes of VSCode, Atom, Sublime Text, IntelliJ, even Neovim clamoring for the top spot in developer mindshare, why consider a 50-some year old Lisp operating system from the stone age? Why embrace its anachronistic language and ecosystem, or struggle against its coiling-into-infinity learning curve when you could be productive on day 2 with just about any other modern editor?

There are many reasons, but it’s greatest asset is undeniably its:

  • Extensibility. Emacs shines in the hands of an experienced user who knows exactly what they need from their tools (and is willing to build them). Certainly, most text editors boast some degree of “programmability”, but none of them hold a candle to:

    • How much of Emacs is configurable,
    • How low the barrier of entry into extending Emacs is,
    • How self-documenting Emacs is,

    Emacs Lisp isn’t a great language, all around, but it’s a great language for exploratory programming and rapid iteration. It gets you from “I want to do X” to “I’m doing X” in fewer steps than any other editor.

  • Emacs’ second greatest asset is its versatility, which is owed to the fact that Emacs isn’t really a text editor, but a platform for plain text applications. You’ll find folks using Emacs for much more than software development:

    • Task planning
    • File management
    • Terminal emulation
    • Email client
    • Remote server tool
    • Git frontend
    • Web client/server
    • and more…

    Emacs can be thought of as a platform to integrate all these applications into one set of consistent keybinds and workflows – a Life IDE, if you will. – Tecosaur [source]

  • Emacs’ ecosystem is home to some amazing plugins: there is no better git porcelain than Magit and no greater ecosystem for personal organization (notes, todo’s, agendas, etc) than Org. They’re so fantastic, folks have tried to port them to other editors with varying success. Still, you can’t beat the originals.
  • Emacs Lisp may not be a particularly good Lisp, but it’s an excellent (and sane) language for rapid iteration and hacking on your editor.

Of course, there are other reasons; Emacs is FOSS, boasts wide and deep integration with a variety of tools and languages, and has a strong ecosystem of users and packages, but in the end, it is up to you to decide if any of these strengths apply to you. Why not Emacs?

The previous section established some of Emacs’ strengths, but Emacs is far from perfect. It has a number of frustrating quirks:

  • Emacs Lisp is anachronistic (no namespaces, most state is global by default, no (true) native concurrency, etc),
  • Emacs is (mostly) single-threaded; when something holds things up, Emacs freezes.
  • Emacs is slow in some respects. Doom exists to mitigate some of this curse, but you’re in for a bad time if you enable all of our most expensive features all at once. (See “Why is Emacs/Doom slow?”; there are workarounds for many instances of slowness).
  • The contribution process for Emacs has a notoriously high barrier of entry (arguing your way through the mailing list has burnt out some notable plugin authors).
  • When something goes wrong, Emacs’ errors can be obtuse.

Even then, if you can get over these, Emacs may not be for you if:

  • You’re a complete beginner to programming, Unix, and the shell.
  • You aren’t interested in (or despise the thought of) learning (Emacs) Lisp.
  • You care little about configuring your editor.
  • You don’t have time to read documentation.
  • You hate parentheses (yes, seriously).
  • You’re terrible at finding answers by yourself.
  • You found Emacs by chasing trends, rather than your personal needs.
  • You expect Emacs to magically reveal to you why you should use it.

3.1.2. TODO Why Doom?

The previous section established Emacs’ strengths and weaknesses, so where does Doom Emacs come in? Doom is a configuration for Emacs meant to address many of its issues, especially those concerning performance, but why exactly should someone use it?

  • Its package manager. Stop micromanaging your plugins and fighting Emacs’ rolling-release package manager. Doom’s is declarative, non-rolling release, and (nominally) reproducible; which is unique on the Emacs starter-kit scene. Don’t let upstream issues surprise you. Roll back or re-pin packages when you don’t have the time to deal with issues. Wield precise control over your packages.

    It also integrates with command line workflows, so automate to your heart’s content.

  • To save time. If you care about personalizing the software you use on a daily basis, even half as much as I do, then you need professional help, but you also know it is time consuming. Emacs out-of-the-box is a wasteland of archaic defaults, full of plugins rife with gotchas and oddities that may or may not be abandonware. It will be an uphill battle. Let Doom deal with all that noise to save yourself some time.

    Time you could otherwise spend attending your daughter’s dance recitals, that baseball game your son’s team almost won last Thursday, or answering the court summons to fight for custody of your kids.

  • It’s a gentler introduction to Emacs. Emacs is hard™. Doom files down its rougher edges.
  • Emacs is slow. Doom can’t promise to resolve all Emacs’ performance issues, but it certainly helps, and it will always be a priority.
  • It can be a barebones framework. Disable all its modules and you get many of Doom’s perks without its opinions; why go vanilla when you can have vanilla + better defaults + a stronger elisp toolchain from the get go?

What it can do for you

  • Better defaults.
  • Faster baseline.
  • Pre-configured modules. Why not Doom?
  • You believe Doom is a barrier to learning Emacs underneath.
  • You have an Emacs config that you’re happy with and don’t have the time/energy to migrate.

3.1.3. TODO Ways to use Doom

  • Use it with out-of-the-box defaults.
  • As a reference.
  • As a barebones foundation for your own config.

3.2. TODO Quickstart

You’re a busy dude[ette] and can’t be bothered with miles of documentation, so here’s the TL;DR version:

  1. Install Emacs.
  2. Install Git and Ripgrep.
  3. Clone doom-emacs to $HOME/.emacs.d.
  4. Modify $DOOMDIR/init.el and customize what modules you want enabled.
  5. Run $ doom install

3.3. TODO Install

3.3.1. TODO Emacs & Dependencies TODO MacOS
TODO With Homebrew
TODO With MacPorts TODO Windows
  • Emacs is inherently slower on Windows.
  • There are more steps to setting up Emacs (and Doom) on Windows.
  • Windows support will always lag behind macOS/Linux support, because I (and many of Doom’s users) don’t use Windows. That means fewer guinea p–I mean, pioneers, willing to test Doom on Windows.

That said, Doom does have happy Windows users (using WSL or scoop/chocolatey).

Help us improve our documentation if you managed to get Doom running on Windows!

With WSL2 + Ubuntu
With a precompiled binary + Git Bash
With chocolatey / scoop TODO Linux
TODO Arch Linux
TODO Void Linux
TODO Gentoo

Everything you need is in Gentoo’s official ::gentoo repository.

TODO Emacs 27

To use Emacs graphically, enable the gui USE flag. And enable the xft USE flag to render fonts correctly (see issue #4876):

echo "app-editors/emacs gui xft" >> /etc/portage/package.use/emacs

To install the latest unmasked version compatible with Doom:

emerge '>=app-editors/emacs-27.0'
  • TODO native-comp

    Alternatively, to install gccemacs/native-comp, use the live ebuild for version 28.0 with the jit USE flag:

    Unmask the desired ebuild by adding the following to package.accept_keywords:

    =app-editors/emacs-28.0.9999 **

    Add the jit USE flag to package.use:

    =app-editors/emacs-28.0.9999 jit

    And emerge:

    emerge =app-editors/emacs-28.0.9999
TODO Other Dependencies
# required
emerge '>=dev-vcs/git-2.23' '>=sys-apps/ripgrep-11.0' sys-apps/findutils
# optional
emerge '>=sys-apps/fd-7.3.0'

3.3.2. TODO Doom Emacs TODO Quick install TODO Manual install TODO Alongside another config
TODO With doom run
TODO With Chemacs v2
TODO With Chemacs v1

3.3.3. TODO Module dependencies

3.4. TODO Update

3.4.1. TODO Rollback

3.4.2. TODO Best practices

3.5. TODO Concepts

Emacs is old. Real old. Some familiar concepts may have names that will catch newcomers off guard.

3.5.1. TODO Emacs terminology User interface

A buffer is a [space in Emacs memory] containing text to be edited. Buffers are used to hold the contents of files that are being [edited or opened]; there may also be buffers that are not visiting files [they display other information like Dired that shows the content of a directory]. […] Each buffer, including the current buffer, may or may not be displayed in any windows.

Echo area

The echo area is the last line of the frame. Unless the minibuffer is active, this is the zone that shows all the messages Emacs sends to the user

The echo area is used for displaying error messages (see Errors), for messages made with the `message` primitive, and for echoing keystrokes. It is not the same as the minibuffer, despite the fact that the minibuffer appears (when active) in the same place on the screen as the echo area.


What the rest of the world calls windows


On graphical displays, Emacs draws fringes next to each window: thin vertical strips down the sides which can display bitmaps indicating truncation, continuation, horizontal scrolling, and so on.

Header line

The header line is like a modeline (extra information line about Emacs current state), that is displayed at the top of each window instead of the bottom of them.

Notable examples include N. Rougier displaying filename in the header line, and LSP-mode powered context information (“breadcrumbs”)

A window can have a header line at the top, just as it can have a mode line at the bottom. The header line feature works just like the mode line feature[…]


A buffer can have blank areas called display margins on the left and on the right. Ordinary text never appears in these areas, but you can put things into the display margins using the `display` property.

Margins tend to be a lot larger than fringes, as margins are at least as wide as characters that you’d want to display there. It is almost always disabled: relevant information can be almost always also be shown in fringes, and fringes take way less screen real estate.


The Minibuffer is the buffer that takes over the last line of your Emacs frame whenever Emacs prompts you (the user) for input.

A minibuffer is a special buffer that Emacs commands use to read arguments more complicated than the single numeric prefix argument. These arguments include file names, buffer names, and command names (as in <kbd>M-x</kbd>). The minibuffer is displayed on the bottom line of the frame, in the same place as the echo area (see The Echo Area), but only while it is in use for reading an argument.

Mode line

What vimmers know as the status line

Each Emacs window (aside from minibuffer windows) typically has a mode line at the bottom, which displays status information about the buffer displayed in the window. The mode line contains information about the buffer, such as its name, associated file, depth of recursive editing, and major and minor modes.


A window is an area of the screen that is used to display a buffer (see Buffers). Editing

Cut (in the Cut/Copy/Paste sense)

Kill functions delete text like the deletion functions, but save it so that the user can reinsert it by yanking . Most of these functions have ‘kill-’ in their name. […] Killed text is saved for later yanking in the kill ring.

Major mode

File types/modes to vimmers/others

Major modes specialize Emacs for editing or interacting with particular kinds of text. Each buffer has exactly one major mode at a time.


The other cursor

The mark specifies a position to bound a range of text for many commands

The mark is also a buffer position like point, but it is only used to mark a region of text in the buffer (between point and mark).

Minor mode

A minor mode provides optional features that users may enable or disable independently of the choice of major mode. Minor modes can be enabled individually or in combination.

Most minor modes implement features that are independent of the major mode, and can thus be used with most major modes. For example, Auto Fill mode works with any major mode that permits text insertion.


Qhat everyone knows as the cursor

point corresponds to the offset in the buffer where the “cursor” is: if point is 3, then text will be inserted at the 3rd character if you type text.

Point is a special buffer position used by many editing commands, including the self-inserting typed characters and text insertion functions. Other commands move point through the text to allow editing and insertion at different places.

Like other positions, point designates a place between two characters (or before the first character, or after the last character), rather than a particular character. Usually terminals display the cursor over the character that immediately follows point; point is actually before the character on which the cursor sits.


The “region” is the active selection.

The text between point and the mark is known as the region . Various functions operate on text delimited by point and the mark, but only those functions specifically related to the region itself are described here.


Paste (contrary to vim)

The most common pitfall to avoid when coming from Vim, is that in Emacs, yanking_ is pasting.

Yanking means inserting text from the kill ring Emacs Lisp

An association list is one of the main datatype used in elisp. It’s a list of key-value cons cells (essentially tuples). Its API can be found in the manual.

An association list or alist is a specially-constructed list whose elements are cons cells. In each element, the CAR is considered a key , and the <small>CDR</small> is considered an associated value. (In some cases, the associated value is stored in the CAR of the CDR.) Association lists are often used as stacks, since it is easy to add or remove associations at the front of the list. For example,

(setq alist-of-colors '((rose . red) (lily . white) (buttercup . yellow)))

sets the variable alist-of-colors to an alist of three elements. In the first element, rose is the key and red is the value.

Doc string

Short for documentation string is information that is embedded in a variable or function. Their docstring can be read when looking up functions with C-h f or variables with C-h v. Keybinds
Universal (prefix) argument

This is a special key you use to modify the command you invoke directly afterwards.

For example, if you take a command called delete-stuff, bound to C-c d that tells you it will “delete the current line, or delete the whole buffer if prefix argument is set”; then

  • C-c d will delete a line
  • M-x delete-stuff RET will delete a line
  • C-u C-c d will delete the whole buffer
  • C-u M-x delete-stuff RET will delete the whole buffer.

The goal of universal and prefix argument is to get a slightly different behaviour for known commands.

Doom users with evil enabled will find the universal argument on SPC u instead than C-u.

Prefix key

A “prefix” is a key that begins a key sequence. For instance, the key sequence C-x C-k b]] is comprised of three distinct input events. Both C-x and C-x C-k can be considered prefixes.

Prefix keys allow to store and move keybindings in groups. For example by default all `LSP-mode` commands are under `SPC c l …`, but if you want to change that prefix to `SPC L …` for all `LSP-mode` commands, it is a one liner in your configuration; you do not have to rebind each command manually to its new `SPC L …` variant.

A prefix key is a key sequence whose binding is a keymap. The keymap defines what to do with key sequences that extend the prefix key. For example, C-x is a prefix key, and it uses a keymap that is also stored in the variable ctl-x-map. This keymap defines bindings for key sequences starting with C-x.

3.5.2. TODO Keybind notation

The Meta key

3.5.3. TODO Special keys TODO The <help> prefix Leader / localleader keys

Doom strives for a totally keyboard driven environment, but there are more commands out there than there are keys on anyone’s keyboard, so many of them are bound under one of two common prefixes, called the leader and local leader keys (these terms are borrowed from Vim):

  • The leader key is a global prefix under which the most common commands are centralized. This is the keyboard analog for the menu bar and ought to be available anywhere.
  • The local leader key (or buffer/mode-local leader key) is a contextual leader prefix. In other words, a prefix whose sub-bindings change depending on what major mode (language) or minor modes you have active.

These two are often referred to in technical writing (and our documentation) as <leader> and <localleader>.

In Doom Emacs, these keys can be found on different prefixes depending on whether you have evil (our vim emulation layer) enabled or not.

  • If evil is enabled:
    • SPC and SPC m in any mode but insert mode, respectively.
    • M-SPC and M-SPC m in insert or emacs mode. (A separate key is needed as not to override the default behavior of SPC to insert whitespace).
  • If evil is disabled: C-c and C-c l instead.

Veteran vimmers may prefer their leader keys on , or \ As with anything in Emacs, this can be customized.

3.5.4. Doom-specific TODO Doom modules TODO $EMACSDIR TODO $DOOMDIR TODO Envvar file bin/doom (Doom’s CLI)

doom is your best friend. It’ll keep all your secrets (mostly because it’s a shell script incapable of sentience and thus incapable of retaining, much less divulging, your secrets to others).

You can run $ doom help to see what it’s capable of, but here are some commands that you may find particularly useful:

$ doom doctor
Diagnose common issues in your environment and list missing external dependencies for your enabled modules.
$ doom sync
Ensures that all missing packages are installed, orphaned packages are removed, and metadata properly generated.
$ doom install
Install any missing packages.
$ doom update
Update all packages that Doom’s (enabled) modules use.
$ doom env
Regenerates your envvar file, which contains a snapshot of your shell environment for Doom Emacs to load on startup. You need to run this for changes to your shell environment to take effect.
$ doom purge -g
Purge orphaned packages (i.e. ones that aren’t needed anymore) and regraft your repos.
$ doom upgrade

Upgrade Doom to the latest version (then update your packages). This is equivalent to:

$ git pull
$ doom sync
$ doom update

3.5.5. Unix $HOME $PATH $SHELL Dotfiles

3.6. TODO Environment

3.7. TODO Configure

3.7.1. TODO Toggling modules

3.7.2. TODO Package management TODO Installing packages TODO Changing an existing recipe TODO Package pinning TODO Disabling packages TODO Registering local packages TODO Recipe specifications

3.7.3. TODO Reconfiguring packages

3.7.4. TODO Major modes

3.7.5. TODO Color themes

There are two ways to load a theme. Both assume the theme is installed and available. You either set doom-theme or manually load a theme with the load-theme function:

;;; add to $DOOMDIR/config.el
(setq doom-theme 'doom-tomorrow-night)
;; or
(load-theme 'doom-tomorrow-night t)

The only difference between the two is when the theme is loaded. Doom loads doom-theme later in the startup process, while calling load-theme will load the theme immediately. If you don’t know which to use, set doom-theme. Installing a third party theme

To install a theme from a third party plugin, say, solarized, you need only install it, then load it:

;;; add to $DOOMDIR/packages.el
(package! solarized-theme)

;;; add to $DOOMDIR/config.el
(setq doom-theme 'solarized-dark)

Don’t forget to run $ doom sync after adding that package! statement to ensure the package is installed. Themes and color schemes

Technically, a theme is a single group of customizations (i.e. variable settings) that are set together.

In practice, themes almost exclusively change the faces of Emacs, that means the ways Emacs chooses fonts and colors for the text it displays.

what CSS devs call styles. A Face in Emacs is a style (font, size, color etc.) applied to text in various places. If some text does not look good to you, it means one of 2 things:
  • It’s applied the wrong face (e.g. font-lock-comments-face instead of vertical-border), so it doesn’t blend with the rest. Usually that means there’s an issue with the package/major-mode you are currently using.
  • The face it has is ill-configured (vertical-border has a bright pink foreground) and it needs change in the theme.
Text properties
Each character in a buffer can have any arbitrary data attached to it, called text properties. The most common one is the face, but you can have any property with any value, if it pleases you. The most common way to set and use text properties is to use overlays, but you can click the link to text properties manual section if you want to go deeper.

Overlays are like highlighting inside a buffer, with extra features.

Like highlighting in a text, an overlay is a zone in a buffer (it has a beginning and an end, and is attached to the buffer it was created for).

On top of that, an overlay can add arbitrary feature to that zone:

  • Change the face of the text in the zone (it can add an actual highlight, or underline the text, or make it red…)
  • Add on-click/hover effects

Possible usages include:

  • recognizing a color in a css file (red, #DEA901), and applying the parsed color as a background to give a live preview
  • add a spell checker that will underline a word and correct it on click
  • show a diagnostic from a compilation error at the correct location and provide a websearch on the error message with a right click
Font Lock
fontification/syntax highlighting

3.7.6. TODO Fonts

Doom exposes five (optional) variables for controlling fonts in Doom, they are:

  • doom-font
  • doom-variable-pitch-font
  • doom-serif-font
  • doom-unicode-font (the fallback font for unicode symbols that your default font doesn’t support)
  • doom-big-font (used for doom-big-font-mode)

They all accept either a font-spec, font string ("Input Mono-12"), or xlfd font string.


;;; Add to $DOOMDIR/config.el
(setq doom-font (font-spec :family "Input Mono Narrow" :size 12 :weight 'semi-light)
      doom-variable-pitch-font (font-spec :family "Fira Sans") ; inherits `doom-font''s :size
      doom-unicode-font (font-spec :family "Input Mono Narrow" :size 12)
      doom-big-font (font-spec :family "Fira Mono" :size 19))

3.7.7. TODO (Re)Binding keys Changing your leader keys

Four variables control what prefixes Doom uses for its leader and localleader keys:

  • For Evil users:

    Variable Default key
    doom-leader-key SPC
    doom-localleader-key SPC m
  • For Emacs and Insert state (evil users), and non-evil users:

    Variable Default evil key Default non-evil key
    doom-leader-key M-SPC C-c
    doom-localleader-key M-SPC m C-c l

When evil is disabled neither doom-leader-key and doom-localleader-key are used. Change doom-leader-alt-key and doom-localleader-alt-key instead.

For example, to change your leader keys to comma and backslash:

;;; add to $DOOMDIR/config.el
(setq doom-leader-key ","
      doom-localleader-key "\\") Binding new keys under the leader prefix

To bind additional leader keys use the map! macro and its :leader keyword:

(map! :leader 
      ;; <leader> x will invoke the dosomething command
      "x" #'dosomething
      ;; <leader> y will print "Hello world" in the minibuffer
      "y" (cmd! (message "Hello world"))
      ;; This unbinds what was previously bound to <leader> f
      "f" nil)

Local leaders keys, on the other hand, require a :map to be specified:

(map! :after python
      :map python-mode-map
      ;; <localleader> x will invoke the dosomething command
      "x" #'dosomething

You’ll notice :after python in the example above. It is important that your keys are bound after the keymap is loaded. In this case, python-mode-map is defined in the python package. See (Re)Binding keys below.“ Binding new leader prefixes

You cannot bind more than one localleader key due to technical imitations, but you can bind multiple leader keys, e.g.

(setq doom-leader-key "SPC")
(map! :map override
      "C-;"   #'doom/leader        ; ctrl + ;
      "M-SPC" #'doom/leader        ; meta + space
      :n ","  #'doom/leader        ; , in normal mode
      :leader "l" #'doom/leader')  ; SPC l

3.7.8. TODO Code formatting

3.7.9. TODO User interface TODO Popup windows

The :ui popup module tries to standardize how Emacs handles “temporary” windows. It includes a set of default rules that tell Emacs where to open them (and how big they should be). Check out its documentation for details on defining your own rules, and documentation on the set-popup-rule! function with <help> f. TODO Line numbers

3.7.10. TODO Keyboard layout

3.7.11. TODO Dashboard

3.7.12. TODO File/directory-local variables

3.7.13. TODO Turning Emacs into an IDE

Doom supports LSP, but it is not enabled by default. To enable it, you must:

  1. Enable the :tools lsp module,
  2. Enable the +lsp flag for the appropriate modules you want LSP support for (e.g. :lang python +lsp or :lang rust +lsp),
  3. Install one of the supported LSP servers through your package manager or other means. That module’s documentation will tell you how to install them, otherwise consult the server table on the lsp-mode project page.
  4. Run $ doom sync on the command line and restart Emacs.

Some language modules may lack LSP support (either because it hasn’t been implemented yet or I’m not aware of it yet – let us know!). To enable LSP for these languages, add this to $DOOMDIR/config.el:

(add-hook 'MAJOR-MODE-local-vars-hook #'lsp!)
;; Replace MAJOR-MODE. e.g. `lisp-mode-local-vars-hook'

3.7.14. TODO Reloading your config

Short answer: You can, but you shouldn’t.

Long answer: Restarting Emacs is always your safest bet, but Doom provides a few tools for experienced Emacs users to skirt around it (most of the time):

  • Evaluate your changes on-the-fly with M-x +eval/region (bound to the gr operator for evil users) or M-x eval-last-sexp (bound to C-x C-e). Changes take effect immediately.
  • On-the-fly evaluation won’t work for all changes. e.g. Changing your doom! block in =$DOOMDIR/init.el.

    But rather than running $ doom sync and restarting Emacs, Doom provides M-x doom/reload for your convenience (bound to <help> r r). This runs $ doom sync, restarts the Doom initialization process and re-evaluates your personal config. However, this won’t clear pre-existing state; Doom won’t unload modules/packages that have already been loaded and it can’t anticipate complications arising from your private config.

  • You can quickly restart Emacs and restore the last session with M-x doom/restart-and-restore (bound to <leader> q r).

3.7.15. TODO Common mistakes

3.8. TODO Troubleshoot

3.8.1. TODO The *Messages* buffer

3.8.2. TODO Debug mode

3.8.3. TODO Hard crashes

3.8.4. TODO Freezing and hangs

3.8.5. TODO Dealing with errors TODO Producing a backtrace

This is a test TODO Startup failures TODO CLI failures TODO Package failures TODO Common error messages
void-function: XYZ
void-variable: XYZ
commandp: XYZ
Key sequence ... starts with non-prefix key ...
unable to find theme file for XYZ
Cannot open load file: No such file or directory, ...
Error in private config: ...
end-of-file ...

3.8.6. TODO Testing in Doom’s sandbox TODO Generating a minimal test case

3.8.7. TODO Bisecting your private config

3.8.8. TODO Bisecting Doom Emacs

4. Migrating

Fresh off the boat from another editor? Perhaps another Emacs config? If things seem too different here, perhaps our migration guides can soothe those transition pains.

Though, if Emacs is completely new to you, I recommend visiting the Concepts section of our manual; it is a quick primer on basic Emacs (and Doom) concepts that may be alien to users coming from other editors.

4.1. Introduction

4.2. TODO From vanilla

4.2.1. Comparison

4.2.2. Gotchas

4.3. TODO From Spacemacs

4.3.1. Comparison

To paraphrase (and expand upon) a reddit answer to this question by @gilbertw1:

  • Doom is lighter than Spacemacs. Doom starts up faster and is better optimized, but Spacemacs has more features.
  • Doom is thinner than Spacemacs. There are fewer abstractions between you and vanilla Emacs, and what abstractions do exist are thin by design. This means there’s less to understand and it’s easier to hack.
  • Doom is much more opinionated than Spacemacs. Doom does not strive to be a one-size-fits-all, beginner-friendly solution, nor is it configured by consensus. It is [mostly] the work of one developer and caters to his vim-slanted tastes. Doom’s defaults enforce very particular (albeit optional) workflows.
  • Doom lacks manpower. Bugs stick around longer, documentation is lighter and development is at the mercy of it’s maintainer’s schedule, health and whims.
  • Doom is not beginner friendly. Doom lacks a large community to constantly improve and produce tutorials/guides for it. Spacemacs is more likely to work right out of the box. Doom also holds your hand less. A little elisp, shell and git-fu will go a long way to ease you into Doom.
  • Doom is managed through it’s command line interface. The bin/doom script allows you to script package management, manage your config, or utilize elisp functionality externally, like org tangling or batch processing.
  • Doom’s package manager is declarative and rolling release is opt-in. Doom takes a little after nix, striving for as much config reproducibility as Emacs (and git) will permit. Spacemacs uses package.el, which is only rolling release.

4.3.2. Gotchas

4.4. TODO From (Neo)Vim

4.4.1. Comparison

4.4.2. Gotchas

4.5. TODO From VSCode

4.5.1. Comparison

4.5.2. Gotchas

5. Tutorials

Now that Doom is installed, your next battle is figuring out how to use it. It’s dangerous to go alone, take these tutorials (and check out our community for more, afterwards):

Our tutorials are a work in progress; many of them are incomplete. Help us complete them.

5.1. TODO Discovery

5.1.1. Keybinds Which-key Describe bindings

5.1.2. Modules

5.1.3. Commands

5.1.4. Packages

5.2. TODO Navigating

5.2.1. Cursor motions

5.2.2. Window manipulation

5.2.3. Opening files

5.2.4. Switching buffers


5.3. TODO Editing

5.3.1. Copy/Paste

5.3.2. Text manipulation

5.3.3. Resize fonts on-the-fly

5.3.4. Region selection

5.3.5. Narrowing

5.3.6. Replacing text

5.3.7. Replacing text in multiple files

5.3.8. Commenting

5.3.9. Deleting, renaming, or moving files

5.3.10. Keyboard macros

5.3.11. Scratch buffer

5.3.12. Reformatting

5.3.13. Expandable snippets

5.4. TODO Searching

5.4.1. Search in current buffer

5.4.2. Search multiple files

5.4.3. Search online

5.4.4. Look up in dictionary/thesaurus

5.4.5. Look up documentation

5.5. TODO Projects

5.6. TODO Programming

5.6.1. LSP and servers

5.6.2. Jump to definition/references

5.6.3. Compiling

5.6.4. Executing code on-the-fly

5.6.5. REPLs

5.6.6. Code completion

5.6.7. Debugger

5.7. TODO Org

5.8. TODO Magit

5.9. TODO Emacs server

5.10. TODO External tools

5.10.1. EditorConfig

5.10.2. Environment managers (conda, virtualenv, direnv, etc)

5.10.3. NixOS

5.11. TODO Workspaces

6. Developer manual

Interested in what twigs and glues we hold the project together with? Our developer’s manual goes over all our conventions and includes guides to walk hackers and contributors through our infrastructure and internal design.

  • Releases – About Doom’s versioning scheme and release schedule
  • Conventions – Doom’s code, project, docs, and keybind conventions
    • Documentation – About the formatting and conventions of our documentation
    • Emacs lisp – Doom’s style guide for code and comments
    • Git branches – How Doom organizes its git repository and formats commits
    • Git commits – How Doom organizes its git repository and formats commits
    • Keybinds – …
  • Forking – How to fork Doom and maintain your own branch
  • Modules – Breaks down Doom modules and how to write them
  • CLI – How to use and extend doom for your own automation
  • CI/CD – Explaining Doom’s automated infrastructure

6.1. TODO Introduction

This documentation is designed for contributors, hackers, and users who want to know:

  • What twigs and glues hold the Doom Emacs project together (e.g. toolchains, CI/CD, our process for releases).
  • What our code, git commit, and documentation conventions are.
  • How Doom’s internals are designed and why.

6.2. TODO Releases

Doom Emacs follows the CalVer versioning scheme (i.e. YY.0M[.PATCH][MODIFIER]) alongside a loose monthly release schedule. This scheme was chosen because Doom consists of many, many third party packages which may break compatibility individually over time. SemVer is still used for Doom’s core, however.

6.2.1. The process

  1. A release-YY.0M branch is created.

6.3. TODO Conventions

6.3.1. TODO Documentation

Welcome to our documentation about the documentation. Here I’ll walk you through how best to navigate our docs and the conventions we use for them – and in such painstaking detail that you’ll memorize it all simply to avoid the horror of revisiting it. You’re welcome. Notice for HTML readers

Our docs are also available from within Doom Emacs. If you already know your way around Doom, its search and navigation facilities can provide a more powerful way to consume them. Access them with M-x doom/help (on <help> d h), if you prefer, otherwise, read on. Formatting

Our documentation consists of a series of Org files living in the project’s docs/* directory, and module-specific documentation in their respective modules/*/*/ file. Each of these should consist of:

  • A standardized navigation bar followed by a 80-character sequence of dashes (do not insert these by hand, use $ doom make docs:menu to generate them). The doom-cli-docs-menu and doom-cli-docs-common-menu variables control the menu items.
  • A #+TITLE. Should be capitalized as per sentence case rules.
  • A #+SUBTITLE to summarize the contents of that file. It should be capitalized as per sentence case rules. Should have no trailing punctuation.
  • A #+SETUPFILE with a relative link to docs/.setupfile (automatically generated with $ doom make docs:conform).
  • No table of contents, unless you use #+STARTUP: unfold. #+STARTUP: content is the default (as specified in docs/ which shows only the headings, which serves as a native ToC (and a ToC is generated in the HTML/PDF export targets).
  • The contents of the file, which should never be more than 6 headings deep.
Special tags

Doom treats certain heading tags especially. They are:

  • :ignore: – This heading will be hidden when doom-docs-mode is active or when the file is exported. It will be as if the contents of that header belonged to its parent tree.
  • :unfold: – This heading will be unfolded at startup. Use this for introduction sections.
  • :noorg: – This whole tree will be hidden when doom-docs-mode is active. Use this on trees that should only be displayed in the HTML/PDF versions of our documentation.
  • :noexport: – This whole tree will be excluded during HTML/PDF export. Use these to display content only to users reading the docs within Doom Emacs.

Doom also uses #+begin_comment ... #+end_comment blocks to hide content from the exported versions of our docs. These lines (i.e. excluding their content) will be hidden when doom-docs-mode is active.


Our documentation is peppered with asides, indicated by an icon. Depending on the icon, their meaning may change, like so:

These are for “under construction” notices or contribution call-to-actions.

These are for technical details, examples, and external references that build on the current subject.

These are for opinions and tangents by the maintainer or a code contributor.

These are time-sensitive annotations or timestamps that are likely to change at some point. e.g. Deprecation notices.

These warn users of pitfalls or important rules.

Continuation lines should be indented with 3 leading characters (to align with the first line).

The doom-snippets package (included in the :editor snippets Doom module) provides the following triggers for creating these quickly:

  • <wip (🔨)
  • <tip (📌)
  • <rant (💡)
  • <time (🕞)
  • <warn (🚧)

After typing them in an org file, press TAB.

  • Inline verbatim blocks for:
    • File paths (e.g. ~/.emacs.d/init.el or $DOOMDIR/config.el)
    • Technical nouns (references to [external] packages, programs, libraries, concepts, versions, etc). e.g.
      • zls is the name of an external package.
      • “Please install git so you can use git” – The first git refers to the system package, the second refers to the executable.
      • Do not use this for proper product names. e.g. Windows 10 vs win10-x86. One is a product name (which should be linked to its homepage), the other is a technical reference to a particular build of Windows.
    • Meta annotations (like DEPRECATED):
    • Referring to org syntax literally. e.g. ~this would normally be a code block~ and this would be *bolded*.
  • Inline code blocks are used for special syntax or
    • ~rg~ or ~doom~ – refers to shell commands.
    • ~M-x some-command~ – is special syntax for issuing a command in Emacs
    • ~+flag~ – is the syntax for a Doom module flag. However, use [[doom-module:][+flag]] instead for references of actual Doom flags.
    • ~display-buffer-alist~ – is a reference to a elisp symbol.
    • [[doom-package:][js2-mode]] installs ~js2-mode~ – first js2-mode refers to an elisp package, the second is a major mode symbol.
  • Complete shell commands should be prefixed with a $ (and never with sudo, unless root access is absolutely necessary), e.g.
    • ~$ doom sync~
    • ~$ git clone ~/.emacs.d~
    • ~rg~ – Not a complete command! Simply a reference to the executable.
  • The verbatim : operator should only be used to inhibit org from interpreting org syntax (i.e. to display text verbatim):

    This *has* /org/ ~syntax~ that we want displayed as-is. TODO Changelogs TODO Modules

If you’re here wondering what a Doom module is, check out our introduction to the concept in the manual.

If you’re here wondering how to enable a Doom module, check out the Toggling Modules section.

If you’re here to better understand a module’s documentation; its structure and formatting, or something else about it, that’s what this section is all about!

TODO Description

A module’s description is an introduction to what the module does and provides. It should stand on its own; with links to any relevant projects. The description will be copied to the module index when running $ doom make module-index, so its contents should remain concise and surface level. Depth should be reserved for its other sections.

The most common components of the description are:

  • A short summary of what it adds to Doom Emacs.
  • A long summary of the features it provides (Code completion, snippets, integration for a particular tool – they should be listed along with any key Emacs packages that provide that functionality).
  • A list of maintainers.
  • A list of module flags.
  • A list of plugins.
  • A list of hacks.
TODO Prerequisites
TODO Troubleshooting

6.3.2. TODO Emacs lisp TODO Style guide

Doom conforms to @bbatsov’s emacs-lisp style guide with the following exceptions:

  • Use mapc instead of seq-do.
  • No hanging parentheses.
  • We use DEPRECATED to indicate code that will eventually be removed.

In addition to our other conventions:

  • Top-level use-package! and after! blocks should be separated with two blank lines. Naming conventions

Doom has a number of naming conventions that it uses in addition to the standard lisp conventions. Third party packages may use their own conventions as well.

Lisp conventions

The lisp conventions are simple. Symbols follow NAMESPACE-SYMBOLNAME for public variables/functions (e.g. bookmark-default-file or electric-indent-mode) and NAMESPACE--SYMBOLNAME for private ones (e.g. byte-compile--lexical-environment and yas--tables).

NAMESPACE is usually the name of the containing file or package. E.g. the company plugin prefixes all its variables/functions with company-.

Doom conventions
Denotes a public command designed to be used interactively, via M-x or a keybinding. e.g. doom/info, +popup/other, +ivy/rg.
A public evil operator, motion or command. e.g. +evil:align, +ivy:rg.
doom-[-]NAME-h or +MODULE-[-]NAME-h
A non-interactive function meant to be used (exclusively) as a hook. e.g. +cc-fontify-constants-h, +flycheck-buffer-h.
doom-[-]NAME-a or +MODULE-[-]NAME-a
Functions designed to be used as advice for other functions. e.g. doom-set-jump-a, doom--fix-broken-smie-modes-a, +org--babel-lazy-load-library-a
doom-[-]NAME-fn or +MODULE-[-]NAME-fn
Indicates an strategy function. A good rule of thumb for what makes a strategy function is: is it interchangeable? Can it be replaced with another function with a matching signature? e.g. +lookup-dumb-jump-backend-fn, +magit-display-buffer-fn, +workspaces-set-project-action-fn

A public Doom “autodef” function or macro. An autodef should always be defined, even if its containing module is disabled (i.e. they will not throw a void-function error). The purpose of this is to avoid peppering module configs with conditionals or after! blocks before using their APIs. They should noop if their module is disabled, and should be zero-cost in the case their module is disabled.

Autodefs usually serve to configure Doom or a module. e.g. after!, set-company-backends!, set-evil-initial-state!

6.3.3. TODO Git branches

Our development (i.e. nightly) branch. Development happens rapidly here; often seeing ~10 commits a day.
Our stable branch. develop is merged into main once all tests are passed.

6.3.4. Git commits

Doom has adopted its own spin-off of conventional commits:




For example:

As of 074b9eb0, use $ doom ci lint-commits HEAD~1 to locally lint your last commit against these rules. Types

For updating pinned packages, including changes to code to reflect changes upstream. Replace bump with revert when downgrading packages.


user/repo@a1b2c3da1b2c -> user/repo@z9y8x7wz9y8x
user/repo@a1b2c3da1b2c -> user/repo@z9y8x7wz9y8x
user/repo@a1b2c3da1b2c -> user/repo@z9y8x7wz9y8x



Work on project infrastructure and development tools: build scripts, CI/CD config files (e.g. .github/*), ignore files, etc.


Changes to documentation, docstrings, and help output from CLI commands (e.g. the output of $ doom help or $ doom doctor).

  • This includes user-facing changes to doctor checks.
  • Use nit for code comments instead.

For changes that introduce a new feature, a major UI/UX change, or add integration support in production code. For example, adding magit-gitflow to the :tools magit module introduces brand new functionality.

However, changes that are minor, or present little-to-no user-facing change, should use the tweak type.


A fix for a bug or misbehavior in production code. Also applicable when updating stale code that was missed last bump.


A merge commit, merging a pull request or branch.

  • Never specify a scope.
  • The bang is meaningless for this type.
  • The SUMMARY should only contain one or more (comma-delimited) pull request references or a branch’s name. e.g. merge: #4129, merge: develop.

These commits reflect changes to our module list. e.g. Adding, removing, renaming, or deprecating modules.

  • Don’t use this for changes within modules.
  • Scope goes after the colon.


module: add :lang zig
module: move :feature evil to :editor evil
module: move :feature vc to :emacs vc, :ui vc-gutter
module: remove :ui fill-column

With Emacs 26.x support dropped and `display-fill-column-indicator-mode'
introduced in Emacs 27.1, this module is reduced to a single line, and
so has become too trivial to warrant remaining a module.
module: deprecate :tools rgb

The module is too trivially small; it's simply one hydra, and :ui hydra
is deprecated, so this module will be next to go.

Nitpick changes that have no effect on the code, such as changes to whitespace, formatting, or comments.


A refactor explicitly for improving startup or runtime performance.


Changes to the code base that does not add a feature nor fix a bug; such as removing redundant code, simplifying code, renaming variables, or swapping one package for a near-enough drop-in replacement.

For example: replacing git-link with browse-at-remote is a refactor because they do the same thing, with slightly different interfaces.


Where VERSION is the new version. A commit of this type marks a version bump. Should only be used by maintainers.


For reverting changes. SUBJECT should consist of:

  • Doom modules or categories (reverting bumps),
  • Packages (reverting bumps),
  • The full unquoted subject of the reverted commit (requires a Revert HASH in FOOTER),

If you revert another commit in a same PR, please rebase the earlier commit out instead before it is merged.


Changes to unit tests, but not testing infrastructure (use dev for that).


For minor UX improvements or tweaks to variables and defaults with subtle or no user-facing changes.

For example: changing the button face’s :box attribute, inserting drop-in functionality (e.g. (setq prefix-help-command 'embark-prefix-helm-command)), or tuning the garbage collector.

Breaking changes
  1. Append a ! (aka bang) to the TYPE to indicate a breaking change.
  2. Prepend BREAKING CHANGE: to BODY, followed by an explanation of what is broken and how to get around it.


refactor!: remove X functionality

BREAKING CHANGE: Without X, A and B will not work. Enable Y to get
similar behavior.
fix!(zig): remove lsp support

BREAKING CHANGE: removing LSP support reduces how much Microsoft you
must ingest to write Zig, but it means no more LSP. Only workaround is
to meme on the internet, especially in obscure git convention guides
that only a handful of people will ever read. Scope

The SCOPE should be one of the following:

  • A module minus the category: nit(python), test(doom-dashboard), dev(popup), docs(everywhere)
  • A category without the module, implying it affects all modules inside: fix(:lang), feat(:editor), …
  • An arbitrary scope prefixed with &: fix(&feature), dev(&org-roam2), feat(&org-knit). Useful for PRs and pending features.
  • One of these special scopes:
    • cli: when it concerns changes to Doom’s CLI: core-cli.el, core/cli/**, or bin/**.
    • lib: when it concerns changes to Doom’s core libraries: core-lib.el or core/autoload/**.
    • For docs commits, these additional scopes are available:
      • The basename (no directory, no extension) of a file in docs/*.org. e.g. for changes to docs/ -> docs(migrate): .... docs/ -> docs(tutorials): ....
      • install (referring to our installation guide)
  • One or more of the above, separated with a comma: feat(python,rust), fix(lsp,debugger), docs(:lang,&org-roam):. However, this is discouraged.

The scope may be omitted if:

  • Is a change to Doom’s global defaults, larger design decisions, or core.
  • Using the bump:, revert:, release:, module:, or merge: types. Their scope belongs in their SUBJECT.

Does your change touch many modules? Only mention the target scope(s). For example, a fix for :tools lsp that affects LSP implementations in other modules only needs to specify lsp as its scope.

Do not put issue/PR references in the commit SUBJECT. See footer below. Summary
  • Can’t be shorter than 10 characters or longer than 72 (<= 50 is ideal).
  • Should be present tense and imperative voice.
    • feat: add X instead of feat: added Y
    • fix: replace A with B instead of fix: replaced A with B
    • When TYPE is a verb, it may be used as part of the SUBJECT:
      • Bad: fix: fix TAB breaking when focus is lost
      • Good: fix: TAB breaking when focus is lost
  • The first word in SUBJECT should not be capitalized – unless it’s a key reference, e.g.
    • Good: fix: TAB breaks when focus is lost
    • Good: fix: remove buggy code
    • Bad: feat: Add new shenanigans
  • Do not quote symbol references and inline code: tweak: gc-cons-threshold = (* 128 1024 1024)
  • Key sequences that are ambiguous in their context should be single quoted:

    • Good: feat: add C-; keybind
    • Good: refactor!: remove C-c C-; keybind
    • Bad: fix: make SPC s m a reality
    • Good: fix: make 'SPC s m' a reality
    • Bad: fix: bind 'SPC '' to ivy-resume
    • Good: fix: bind "SPC '" to ivy-resume

    A single quote is preferred. Switch to double quote if ' is present in sequence, otherwise backquote. If all three characters are present, know that the ancient ones don’t take kindly to your summoning methods (i.e. you should rethink your subject line). Body

BODY is optional. There are no restrictions on tense or voice, but must be grammatically correct and must adhere to the following:

  • Standard grammar and formatting rules apply:
    • Sentences are separated with one space.
    • Paragraphs are not indented and separated with a blank line.
  • Line width must not exceed 72 characters, except for machine-generated lines (e.g. bump commit lines) or long URLs.
  • A BREAKING CHANGE: line and explanation is required if you use a banged type (e.g. feat!: ..., fix!: ...).
  • Include user/repo@HASH -> user/repo@HASH lines in bump commits (or revert commits where packages are “un”-bumped).
  • Key sequences that are ambiguous in their context should be single quoted:
    • Bad: I changed SPC s m a to...
    • Good: I changed 'SPC s m a' to...
    • Good: The TAB key was fixed Footer

The FOOTER consists of two sections: the references then git meta lines, separated by a blank line.

Each reference line should be comprised of:

  • A keyword followed by a single space:
    • Ref: a reference for readers to consult for more information
    • Fix: use for issues/commits
    • Close: use for PRs
    • Revert: required for revert: ... commits
  • Then a single reference:
    • An issue or PR reference: #123, user/repo#123, https://git.forge.fake/repo#123
    • A 12-character commit: 3bedae38dd9f, user/repo@3bedae38dd9f, https://git.forge.fake/repo@3bedae38dd9f
    • An URL to an external resource.


Close #55
Close user/repo#952
Fix #1
Fix #25
Fix https://git.forge.fake/repo#123
Fix user/repo#84
Ref #4
Ref #5
Ref 3bedae38dd9f
Ref https://git.forge.fake/repo#123
Ref user/repo#25
Ref user/repo@3bedae38dd9f
Revert 3bedae38dd9f
Co-authored-by: John Doe <>
Signed-off-by: Jane Doe <>

Lines should be grouped by keyword, but precise order is unimportant.

6.3.5. TODO Keybinds TODO Modifiers TODO Leader TODO Localleader TODO Evil TODO Vanilla

6.4. TODO Forking

6.5. TODO Modules

Functionality in Doom is divided into collections of code called modules (à la Spacemacs’ layers). A module is a bundle of packages, configuration and commands, organized into a unit that can be enabled or disabled by adding or removing them from your doom! block in $DOOMDIR/init.el.

6.5.1. Introduction Concepts
  • features
  • autoloading
  • autodefs
  • deferred loading
  • use-package Module notation Load order Conventions

6.5.2. TODO Anatomy of a module TODO TODO init.el TODO config.el TODO packages.el TODO cli.el TODO doctor.el TODO autoload.el TODO autoload/ TODO test/ TODO patches/ TODO Other files

6.5.3. TODO Doom Emacs loading process

6.5.4. TODO Examples

6.5.5. TODO Best practices

6.6. TODO Command line interface


  • Current stack
  • CI files & directories

6.7.1. TODO Workflows TODO Testing TODO Linting commits TODO Bumping packages TODO Building docs

6.7.2. TODO Possible improvements

7. Modules

Doom’s features are divided into modules; a module is a collection of packages, configuration, and commands, organized into a unit that can be easily enabled or disabled by adding or removing them from your doom! block in $DOOMDIR/init.el (remember to run $ doom sync and restart Emacs after changing your doom! block).

Looking for technical documentation on how Doom’s modules work and are designed? That’s in our developer’s manual.


7.1. :app

Application modules are complex and opinionated modules that transform Emacs toward a specific purpose. They may have additional dependencies and should be loaded last, before :config modules.

7.1.1. calendar

Watch your missed deadlines in real time

This module adds a calendar view for Emacs, with org and google calendar sync support.

7.1.2. emms

A media player for music no one’s heard of

This module enables Emacs to be used as a music player. It uses mpd as a backend server and mpc to update your music database.

7.1.3. everywhere

*leave* Emacs!? You must be joking

This module adds system-wide popup Emacs windows for quick edits.

7.1.4. irc

How neckbeards socialize

This module turns Emacs into an IRC client, capable of OS notifications.

7.1.5. rss

Flags: +org

An RSS reader that Google can’t shut down

Read RSS feeds in the comfort of Emacs.

7.1.6. twitter

Be superficial in plain text

Enjoy twitter from emacs.

  • View various timelines side by side, e.g. user’s timeline, home, etc.
  • Post new tweets
  • Send direct messages
  • Retweet
  • Follow and un-follow users
  • Favorite tweets

7.2. :checkers

For modules dedicated to linting text.

7.2.1. grammar

Tasing grammar mistake every you make

This module adds grammar checking to Emacs to aid your writing by combining lang-tool and writegood-mode.

7.2.2. spell

Flags: +aspell +enchant +everywhere +flyspell +hunspell

Tasing you for misspelling mispelling

This modules provides spellchecking powered by aspell, hunspell or enchant.

Spellcheck is automatically loaded in many text-mode derivatives, which includes org-mode, markdown-mode, the Git Commit buffer (from magit), mu4e-compose-mode, and others.

  • Spell checking and correction using aspell, hunspell or enchant.
  • Ignores source code inside org or markdown files.
  • Lazily spellchecking recent changes only when idle.
  • Choosing suggestions using completion interfaces (ivy or helm).

7.2.3. syntax

Flags: +childframe

Tasing you for every semicolon you forget

This module provides syntax checking and error highlighting, powered by flycheck.

7.3. :completion

These modules provide interfaces and frameworks completion, including code completion.

7.3.1. company

Flags: +childframe +tng

The ultimate code completion backend

This module provides code completion, powered by company-mode. It is required for code completion in many of Doom’s :lang modules.


7.3.2. helm

Flags: +childframe +fuzzy +icons

the *other* search engine for love and life

This module provides Helm integration for a variety of Emacs commands, as well as a unified interface for project search and replace, powered by ripgrep.

7.3.3. ido

A foil for other search engines

Interactive DO things. The completion engine that is mostly built-into Emacs.

7.3.4. ivy

Flags: +childframe +fuzzy +icons +prescient

Yesterday's lightest search engine

This module provides Ivy integration for a variety of Emacs commands, as well as a unified interface for project search and replace, powered by ripgrep.

I prefer ivy over ido for its flexibility. I prefer ivy over helm because it’s lighter, simpler and faster in many cases.

7.3.5. vertico

Flags: +icons

The search engine for life and love

This module enhances the Emacs search and completion experience, and also provides a united interface for project search and replace, powered by ripgrep.

It does this with several modular packages focused on enhancing the built-in completing-read interface, rather than replacing it with a parallel ecosystem like ivy and helm do. The primary packages are:

  • Vertico, which provides the vertical completion user interface
  • Consult, which provides a suite of useful commands using completing-read
  • Embark, which provides a set of minibuffer actions
  • Marginalia, which provides annotations to completion candidates
  • Orderless, which provides better filtering methods

7.4. :config

Modules that configure Emacs one way or another, or focus on making it easier for you to customize it yourself. It is best to load these last.

7.4.1. default

Reasonable defaults for reasonable people

This module provides a set of reasonable defaults, including:

  • A Spacemacs-esque keybinding scheme
  • Extra Ex commands for evil-mode users
  • A configuration for (almost) universally repeating searches with ; and ,

7.4.2. literate

Disguise your config as documentation

This module enables support for a literate config.

A literate config consists of a $DOOMDIR/ All src blocks within are tangled $DOOMDIR/config.el, by default, when $ doom sync is executed.

7.5. :editor

For modules concerned with the insertion, manipulation, and general editing of text. Amen.

7.5.1. evil

Flags: +everywhere

Come to the dark side, we have cookies

This holy module brings the vim experience to Emacs.

7.5.2. file-templates

Fill the void in your empty files

This module adds file templates for blank files, powered by yasnippet.

7.5.3. fold

What you can't see won't hurt you

This module marries hideshow, vimish-fold, and outline-minor-mode to bring you marker, indent and syntax-based code folding for as many languages as possible.

7.5.4. format

Flags: +onsave

Standardize your ugly code

This module integrates code formatters into Emacs. Here are some of the formatters that it currently supports:

asmfmt, black, brittany, cabal-fmt, clang-format, cmake-format, dartfmt, dfmt, dhall format, dockfmt, elm-format, emacs, fishindent, fprettify, gleam format, gofmt, iStyle, jsonnetfmt, ktlint, latexindent, ledger-mode, lua-fmt, mix format, nixfmt, node-cljfmt, ocp-indent, perltidy, prettier, purty, rufo, rustfmt, scalafmt, script shfmt, snakefmt, sqlformat, styler, swiftformat, tidy

7.5.5. god


Adds god-mode support to Doom Emacs, allowing for entering commands without modifier keys, similar to Vim’s modality, separating command mode and insert mode.

7.5.6. lispy

Vim for lisp, for people who don't like vim

This module adds lispy key functionality in Lisp languages, including:

  • Common Lisp
  • Emacs Lisp
  • Scheme
  • Racket
  • Hy
  • LFE
  • Clojure
  • Fennel

If :editor evil is enabled, lispyville would also be activated for every mode where lispy is active

The default key themes that are set are as follows:

'((operators normal)
  (prettify insert)
  (atom-movement normal visual)

To change the key themes set lispyville-key-theme. Think of lispyville-key-theme as the equivalent of parinfer-extensions. See lispyville’s README for more info on the specific keybindings of each key theme (starting here).

7.5.7. multiple-cursors

Make all your mistakes at the same time

This module adds a multiple cursors implementation to Emacs (two, if you use evil) that loosely take after multi-cursors in modern editors, like Atom or Sublime Text.

7.5.8. objed

Flags: +manual

Text object editing for the innocent

This modules adds objed, a global minor-mode for navigating and manipulating text objects. It combines the ideas of versor-mode and other editors like Vim or Kakoune and tries to align them with regular Emacs conventions.

This module is incompatible with the :editor evil. Enabling them both will cause errors.

See the objed project README for information on keybinds and usage.

7.5.9. parinfer

For lispers that like Python more (i.e. nobody)

Parinfer is a minor mode that aids the writing of Lisp code. It automatically infers parenthesis matching and indentation alignment, keeping your code balanced and beautiful.


The original parinfer-mode has been deprecated and superceded by parinfer-rust-mode, which has much better performance.

7.5.10. rotate-text

The only back'n'forth nerds will ever know

This module adds text rotation; the ability to cycle through keywords or text patterns at point. e.g. Swapping true and false.

7.5.11. snippets

My elves type so I don't have to

This module adds snippet expansions to Emacs, powered by yasnippet.

7.5.12. word-wrap

Soft-wrapping with language-aware indent

This module adds a minor-mode +word-wrap-mode, which intelligently wraps long lines in the buffer without modifying the buffer content.

7.6. :emacs

Modules in this category augment and extend the built-in features of Emacs.

7.6.1. dired

Flags: +icons +ranger

Making dired pretty [functional]

This module provides reasonable defaults and augmentations for dired.

7.6.2. electric

Shocking keyword-based electric-indent

This module augments the built-in electric package with keyword-based indentation (as opposed to character-based).

7.6.3. ibuffer

Flags: +icons

Edit me like your French buffers

This module augments the built-in ibuffer package.

  • Adds project-based grouping of buffers
  • Support for file-type icons
  • Uses human-readable file-size

7.6.4. tramp

(No description)

7.6.5. undo

Flags: +tree

Persistent, smarter undo for your inevitable mistakes

This module augments Emacs’ built-in undo system to be more intuitive and to persist across Emacs sessions.

7.6.6. vc

Be the difference you want to see in the fringe

This module augments Emacs builtin version control support and provides better integration with git.

7.7. :email

Modules that turn Emacs in an email client.

7.7.1. mu4e

Flags: +gmail +org

The great filter Hanson hadn't anticipated

This module makes Emacs an email client, using mu4e.

  • Tidied mu4e headers view, with flags from all-the-icons.
  • Consistent coloring of reply depths (across compose and gnus modes).
  • Prettified mu4e:main view.
  • Cooperative locking of the mu process. Another Emacs instance may request access, or grab the lock when it’s available.
  • org-msg integration with +org, which can be toggled per-message, with revamped style and an accent color.
  • Gmail integrations with the +gmail flag.
  • Email notifications with mu4e-alert, and (on Linux) a customised notification style.

I want to live in Emacs, but as we all know, living is incomplete without email. So I prayed to the text editor gods and they (I) answered. Emacs+evil’s editing combined with org-mode for writing emails? Yes please.

It uses mu4e to read my email, but depends on offlineimap (to sync my email via IMAP) and mu (to index my mail into a format mu4e can understand).

7.7.2. notmuch

Flags: +afew +org

Closest Emacs will ever be to multi-threaded

This module turns Emacs into an email client using notmuch.

7.7.3. wanderlust

Flags: +gmail

To boldly go where no mail has gone before

This module has no description. Write one?

7.8. :input

(No description)

7.8.1. chinese

Spend your 3 hours a week in Emacs

This module adds support for traditional Chinese script by introducing two input methods: Pinyin and Wubi.

7.8.2. japanese

Ah, a man of culture

This module adds support for Japanese script.

7.8.3. layout

Flags: +azerty +bepo

auie,ctsrnm is the superior home row

This module provides barebones support for using Doom with non-qwerty keywoard layouts.

7.9. :lang

These modules specialize in integration particular languages and their ecosystems into (Doom) Emacs.

7.9.1. agda

Types of types of types of types...

This module adds support for the agda programming language. The Emacs support exists directly in the agda repository but not in melpa.

7.9.2. beancount

Flags: +lsp

Mind the GAAP

This module adds support for Beancount to Emacs. Beancount, like ledger, lets you manage your money in plain text.

7.9.3. cc

Flags: +lsp

C > C++ == 1

This module adds support for the C-family of languages: C, C++, and Objective-C.

  • Code completion (company-irony)
  • eldoc support (irony-eldoc)
  • Syntax-checking (flycheck-irony)
  • Code navigation (rtags)
  • File Templates (c-mode, c++-mode)
  • Snippets (cc-mode, c-mode, c++-mode)
  • Several improvements to C++11 indentation and syntax highlighting.

7.9.4. clojure

Flags: +lsp

Java with a lisp

This module adds support for the Clojure(Script) language.

  • Interactive development environment (cider): REPL, compilation, debugging, running tests, definitions & documentation lookup, code completion, and much more
  • Refactoring (clj-refactor)
  • Linting (clj-kondo), requires :checkers syntax
  • LSP support (clojure-lsp)

7.9.5. common-lisp

If you've seen one lisp, you've seen them all

This module provides support for Common Lisp and the Sly development environment. Common Lisp is not a single language but a specification, with many competing compiler implementations. By default, Steel Bank Common Lisp (SBCL) is assumed to be installed, but this can be configured.

Common Lisp benefits from a mature specification and rich standard library. Thanks to its powerful REPL and debugger, it boasts an “interactive programming” style often unseen in other languages. Compiled Common Lisp programs are trusted to run unmodified for a long time.

7.9.6. coq

Proofs as programs

This module adds coq support, powered by Proof General.

7.9.7. crystal

Ruby at the speed of c

This modules adds crystal support.

  • Syntax-checking (flycheck)
  • REPL (inf-crystal)

7.9.8. csharp

Flags: +dotnet +lsp +unity

Unity, .NET, and mono shenanigans

This module adds C# support to Emacs, powered by Omnisharp (directly or through LSP).

7.9.9. dart

Flags: +flutter +lsp

Paint ui and not much else

Dart is a client-optimized language by Google for fast apps on any platform. It is fast and optimized for UI, famous for the Flutter framework, also made by Google. Both Flutter and Dart are free and open-source.

This module wraps dart-mode, with LSP features like code completion for .dart files, syntax highlighting, debugging, closing labels, etc.

7.9.10. data

A dumping ground for data formats

This module adds Emacs support for CSV and XML files.

7.9.11. dhall

Config as code

This module adds Dhall language support to Emacs.

Dhall is a programmable configuration language that you can think of as: JSON + functions + types + imports.

7.9.12. elixir

Flags: +lsp

Erlang done right

This module provides support for Elixir programming language via alchemist or elixir-ls.

7.9.13. elm

Flags: +lsp

Care for a cup of TEA?

This module adds Elm support to Doom Emacs.

7.9.14. emacs-lisp

A parsel-tongue for the oldest serpent

This module extends support for Emacs Lisp in Doom Emacs.

  • Macro expansion
  • Go-to-definitions or references functionality
  • Syntax highlighting for defined and quoted symbols
  • Replaces the built-in help with the more powerful helpful
  • Adds function example uses to documentation

7.9.15. erlang

Flags: +lsp

An elegant language for a more civilized age

This module provides support Erlang programming language. Support for the sourcer language server is optional.


7.9.16. ess

Flags: +stan

73.6% of all statistics are made up

This module adds support for various statistics languages, including R, S-Plus, SAS, Julia and Stata.

7.9.17. factor


This module adds support to the factor programming language and its associated fuel emacs plugin.

7.9.18. faust

DSP, but you get to keep your soul

Add support to Faust language inside emacs.

  • Faust code syntax highlighting and indentation
  • Project-based (inter-linked Faust files)
  • Build/compile with output window
  • Graphic diagrams generation and visualization in the (default) browser
  • Browse generated C++ code inside Emacs
  • Inter-linked files/buffers :
    • From “component” to Faust file
    • From “include” to Faust library file
  • From error to line number
  • From function name to online documentation
  • Fully configurable (build type/target/architecture/toolkit, keyboard shortcuts, etc.)
  • Automatic keyword completion (if Auto-Complete is installed)
  • Automatic objets (functions, operators, etc.) template insertion with default sensible values (if :editor snippets is enabled)
  • Modeline indicator of the state of the code

7.9.19. fsharp

Flags: +lsp

ML stands for Microsoft's Language

This module adds F# support to Doom Emacs.

7.9.20. fstar

(Dependent) types and (monadic) effects and Z3

This module adds F* support, powered by fstar-mode.el.

  • Syntax highlighting
  • Interactively process F* files one definition at a time
  • Query the running F* process to look up definitions, documentation, and theorems

7.9.21. gdscript

Flags: +lsp

the language you waited for

This module adds support for GDScript, the scripting language of the Godot game engine, to Doom Emacs, powered by gdscript-mode.

7.9.22. go

Flags: +lsp

The hipster dialect

This module adds Go support, with optional (but recommended) LSP support via gopls.

  • Code completion (gocode)
  • Documentation lookup (godoc)
  • Eldoc support (go-eldoc)
  • REPL (gore)
  • Syntax-checking (flycheck)
  • Auto-formatting on save (gofmt) (requires :editor format +onsave)
  • Code navigation & refactoring (go-guru)
  • File templates
  • Snippets
  • Generate testing code (go-gen-test)
  • Code checking (flycheck-golangci-lint)

7.9.23. haskell

Flags: +lsp

A language that's lazier than I am

This module adds Haskell support to Doom Emacs.

7.9.24. hy

(No description)

7.9.25. idris

A language you can depend on

This module adds rudimentary Idris support to Doom Emacs.

7.9.26. java

Flags: +lsp +meghanada

The poster child for carpal tunnel syndrome

This module adds Java support to Doom Emacs, including android-mode and groovy-mode.

7.9.27. javascript

Flags: +lsp


This module adds JavaScript and TypeScript support.

7.9.28. json

Flags: +lsp

At least it ain't XML

This module adds JSON support to Doom Emacs.

7.9.29. julia

Flags: +lsp

A better, faster MATLAB

This module adds support for the Julia language to Doom Emacs.

7.9.30. kotlin

Flags: +lsp

A Java(Script) that doesn't depress you

This module adds Kotlin support to Doom Emacs.

7.9.31. latex

Flags: +cdlatex +fold +latexmk +lsp

Writing papers in Emacs has never been so fun

Provide a helping hand when working with LaTeX documents.

  • Sane defaults
  • Fontification of many popular commands
  • Pretty indentation of wrapped lines using the adaptive-wrap package
  • Spell checking with flycheck
  • Change PDF viewer to Okular or latex-preview-pane
  • Bibtex editor
  • Autocompletion using company-mode
  • Compile your .tex code only once using LatexMk

7.9.32. lean

For folks with too much to prove

This module adds support for the Lean programming language to Doom Emacs.

7.9.33. ledger

Be audit you can be

This module adds support for ledger files. Ledger is a command line double-entry accounting system that works with simple text files holding transactions in the following format:

2015/10/12 Exxon
    Expenses:Auto:Gas                         $10.00
    Liabilities:MasterCard                   $-10.00

This modules enables the following features:

  • Syntax and indentation support for ledger files
  • Add, edit, and delete transactions
  • Generate reports
  • Schedule transactions
  • Sort transactions
  • Display statistics about transactions
  • Display balance up to a point

7.9.34. lua

Flags: +fennel +lsp +moonscript

One-based indices? one-based indices

This module adds Lua support to Doom Emacs.

  • REPL
  • Love2D specific functions
  • Moonscript support
  • Fennel support

7.9.35. markdown

Flags: +grip

Write docs for people to ignore

This module provides Markdown support for Emacs.

Markdown is a text-to-HTML conversion tool for web writers. Markdown allows you to write using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid XHTML (or HTML).

Thus, “Markdown” is two things: (1) a plain text formatting syntax; and (2) a software tool, written in Perl, that converts the plain text formatting to HTML. See the Syntax page for details pertaining to Markdown’s formatting syntax. You can try it out, right now, using the online Dingus.

The overriding design goal for Markdown’s formatting syntax is to make it as readable as possible. The idea is that a Markdown-formatted document should be publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions. While Markdown’s syntax has been influenced by several existing text-to-HTML filters, the single biggest source of inspiration for Markdown’s syntax is the format of plain text email. – John Gruber

7.9.36. nim

Python + lisp at the speed of C

This module adds Nim support to Doom Emacs.

7.9.37. nix

I hereby declare "nix geht mehr!"

This module adds support for the Nix language to Doom Emacs, along with tools for managing Nix(OS).


  • Syntax highlighting
  • Completion through company and/or helm
  • Nix option lookup
  • Formatting (nixfmt)

7.9.38. ocaml

Flags: +lsp

An objective camel

This module adds OCaml support to Doom Emacs, powered by tuareg-mode.

7.9.39. org

Flags: +brain +dragndrop +gnuplot +hugo +ipython +journal +jupyter +noter +pandoc +pomodoro +present +pretty +roam +roam2

Organize your plain life in plain text

This module adds org-mode support to Doom Emacs, along with a number of adjustments, extensions and reasonable defaults to make it more performant and intuitive out of the box:

  • A custom, centralized attachment system that stores files in one place, rather than in the same directory as the input file(s) (only applies to attachments from files in/under org-directory).
  • Executable code blocks with support for a variety of languages and tools (depending on what :lang modules are enabled).
  • Supports an external org-capture workflow through the bin/org-capture shell script and +org-capture/open-frame.
  • A configuration for using org-mode for slide-show presentations or exporting org files to reveal.js slideshows.
  • Drag-and-drop support for images (with inline preview) and media files (drops a file icon and a short link) (requires +dragndrop flag).
  • Integration with pandoc, ipython, jupyter, reveal.js, beamer, and others (requires flags).
  • Export-to-clipboard functionality, for copying text into formatted html, markdown or rich text to the clipboard (see +org/export-to-clipboard and +org/export-to-clipboard-as-rich-text).

Org is a system for writing plain text notes with syntax highlighting, code execution, task scheduling, agenda management, and many more. The whole idea is that you can write notes and mix them with references to things like articles, images, and example code combined with the output of that code after it is executed.

7.9.40. php

Flags: +hack +lsp

Perl's insecure younger brother

This module adds support for PHP 5.3+ (including PHP7) to Doom Emacs.

  • ctags-based code completion (company-php and phpctags)
  • eldoc support (ac-php and php-extras)
  • REPL (php-boris)
  • Code refactoring commands (php-refactor-mode)
  • Unit-test commands (phpunit)
  • Support for laravel and composer projects (with project-specific snippets)
  • File templates
  • Snippets

PHP was the first programming language I got paid to code in, back in the Cretaceous period (2003). My sincerest apologies go out to all the programmers who inherited my earliest PHP work. I know you’re out there, writhing in your straitjackets.

Save a programmer today. Stop a friend from choosing PHP as their first language.

7.9.41. plantuml

Diagrams to confuse people more

This module adds plantuml support to Emacs; allowing you to generate diagrams from plain text.

7.9.42. purescript

Flags: +lsp

Javascript, but functional

This module adds Purescript support to Doom Emacs.

7.9.43. python

Flags: +conda +cython +lsp +poetry +pyenv +pyright

Beautiful is better than ugly

This module adds Python support to Doom Emacs.

7.9.44. qt

The cutest GUI framework ever

This module provides language functionality for Qt specific files.

  • Syntax highlighting for qml files
  • Syntax highlighting for .pro and .pri files used by qmake

7.9.45. racket

Flags: +lsp +xp

The DSL for DSLs

This module adds support for the Racket programming language to Doom Emacs.

7.9.46. raku

The artist formerly known as perl6

This module adds support for the Raku programming language to Doom Emacs.

7.9.47. rest

Emacs as a REST client

This module turns Emacs into a REST client.

  • Code-completion (company-restclient)
  • Code evaluation
  • Imenu support for restclient-mode
  • org-mode: babel support (ob-restclient)

restclient-mode is tremendously useful for automated or quick testing REST APIs. My workflow is to open an org-mode buffer, create a restclient source block and hack away. restclient-mode and company-restclient power this arcane wizardry.

7.9.48. rst

ReST in peace

This module adds ReStructured Text support to Doom Emacs.

7.9.49. ruby

Flags: +chruby +lsp +rails +rbenv +rvm

1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"}

This module add Ruby and optional Ruby on Rails support to Emacs.

7.9.50. rust

Flags: +lsp


This module adds support for the Rust language and integration for its tools, e.g. cargo.

  • Code completion (racer or an LSP server)
  • Syntax checking (flycheck)
  • LSP support (for rust-analyzer and rls) (rustic)
  • Snippets

7.9.51. scala

Flags: +lsp

Java, but good

This module adds scala and sbt support to Doom Emacs.

Through the power of Metals (LSP) this module offers:

  • Goto Definition
  • Completions
  • Hover
  • Paremeter Hints
  • Find References
  • Run/Debug
  • Find Implementations
  • Rename Symbol
  • Code Actions
  • Document Symbols
  • Formatting
  • Folding
  • Organize Imports

7.9.52. scheme

Flags: +chez +chibi +chicken +gambit +gauche +guile +kawa +mit +racket

A fully conniving family of lisps

This module provides support for the Scheme family of Lisp languages, powered by geiser.

7.9.53. sh

Flags: +fish +lsp +powershell

She sells {ba,z,fi}sh shells on the C xor

This module adds support for shell scripting languages (including Powershell and Fish script) to Doom Emacs.

7.9.54. sml


THis module adds SML (Standard ML) programming language support to Doom Emacs.

7.9.55. solidity

Do you need a blockchain? No.

This module adds Solidity support to Doom Emacs.

7.9.56. swift

Flags: +lsp

We asked for emoji variables?

This module adds support for the Swift programming language to Doom Emacs.

7.9.57. terra

Earth and Moon in alignment for performance.

\(No description yet\)

7.9.58. web

The tubes

This module adds support for various web languages, including HTML5, CSS, SASS/SCSS, Pug/Jade/Slim, and HAML, as well as various web frameworks, like ReactJS, Wordpress, Jekyll, Phaser, AngularJS, Djano, and more.

7.9.59. yaml

Flags: +lsp

JSON, but readable

This module provides support for the YAML file format to Doom Emacs.

7.9.60. zig

Flags: +lsp

C, but simpler

This module adds Zig support, with optional (but recommended) LSP support via zls.

  • Syntax highlighting
  • Syntax-checking (flycheck)
  • Code completion and LSP integration (zls)

7.10. :os

(No description)

7.10.1. macos

Compatibility for our favorite walled garden

This module provides extra functionality for macOS.

7.10.2. tty

Flags: +osc

Make TTY Emacs suck less

This module configures Emacs for use in the terminal, by providing:

  • System clipboard integration (through an external clipboard program or OSC-52 escape codes in supported terminals).
  • Cursor-shape changing across evil states (requires a terminal that supports it).
  • Mouse support in the terminal.

7.11. :term

What’s an operating system without a terminal? The moduels in this category bring varying degrees of terminal emulation into Emacs.

If you can’t decide which to choose, I recommend vterm or eshell. :term vterm offers that best terminal emulation available but requires a few extra steps to get going. :term eshell works everywhere that Emacs runs, even Windows, and provides a shell entirely implemented in Emacs Lisp.

7.11.1. eshell

The elisp shell that works everywhere

This module provides additional features for the built-in Emacs Shell

The Emacs Shell or eshell is a shell-like command interpreter implemented in Emacs Lisp. It is an alternative to traditional shells such as bash, zsh, fish, etc. that is built into Emacs and entirely cross-platform.

7.11.2. shell

A REPL for your shell

Provides a REPL for your shell.

shell is more REPL than terminal emulator. You can edit your command line like you would any ordinary text in Emacs – something you can’t do in term (without term-line-mode, which can be unstable) or vterm.

Due to shell’s simplicity, you’re less likely to encounter edge cases (e.g. against your shell config), but it’s also the least capable. TUI programs like htop or vim won’t work in shell directly, but will be launched in a term buffer – which handles them reasonably well.

7.11.3. term

It's terminal

(No description)

7.11.4. vterm

As good as terminal emulation gets in Emacs

This module provides a terminal emulator powered by libvterm. It is still in alpha and requires a component be compiled (

vterm is as good as terminal emulation gets in Emacs (at the time of writing) and the most performant, as it is implemented in C. However, it requires extra steps to set up:

  • Emacs must be built with dynamic modules support,
  • and must be compiled, which depends on libvterm, cmake, and libtool-bin.

vterm will try to automatically build when you first open it, but this will fail on Windows, NixOS and Guix out of the box. Install instructions for nix/guix can be found in the :term vterm module’s documentation. There is no way to install vterm on Windows that I’m aware of (but perhaps with WSL?).

7.12. :tools

Modules that integration external tools into Emacs.

7.12.1. ansible

Allow silly people to focus on silly things

(No description)

7.12.2. biblio

(No description)

7.12.3. debugger

Flags: +lsp

Step through code to help you add bugs

Introduces a code debugger to Emacs, powered by realgud or dap-mode (LSP).

This document will help you to configure dap-mode Native Debug(GDB/LLDB) as there is still not enough documentation for it.

7.12.4. direnv

Save (or destroy) the environment at your leisure

This module integrates direnv into Emacs.

direnv is an environment switcher for the shell. It knows how to hook into bash, zsh, tcsh, fish shell and elvish to load or unload environment variables depending on the current directory. This allows project-specific environment variables without cluttering the ~/.profile file.

Before each prompt, direnv checks for the existence of a “.envrc” file in the current and parent directories. If the file exists (and is authorized), it is loaded into a bash sub-shell and all exported variables are then captured by direnv and then made available to the current shell.

7.12.5. docker

Flags: +lsp

Yo dawg, I heard you like OSes, so I…

This module allows you to manipulate Docker images, containers, and more from Emacs.

Provides a major dockerfile-mode to edit Dockerfiles. Additional convenience functions allow images to be built easily.

docker-tramp offers TRAMP support for Docker containers.

7.12.6. editorconfig

Someone else can argue about tabs and spaces

This module integrates EditorConfig into Emacs, allowing users to dictate code style on a per-project basis with an .editorconfig file (formal specification).

7.12.7. ein

Tame Jupyter notebooks with emacs

Adds Jupyter notebook integration into Emacs.

7.12.8. eval

Flags: +overlay

Run code, run (also, repls)

This modules adds inline code evaluation support to Emacs and a universal interface for opening and interacting with REPLs.

7.12.9. gist

A pastebin for Githubsters

Adds the ability to manage, pull from, or push to your Gists from within Emacs.

7.12.10. lookup

Flags: +dictionary +docsets +offline

Navigate your labyrinthine code and docs

This module adds code navigation and documentation lookup tools to help you quickly look up definitions, references, documentation, dictionary definitions or synonyms.

  • Jump-to-definition and find-references implementations that just work.
  • Powerful xref integration for languages that support it.
  • Search online providers like, stackoverflow, google, duckduckgo, or youtube (duckduckgo and google have live suggestions).
  • Integration with docsets.
  • Support for online (and offline) dictionaries and thesauruses.

7.12.11. lsp

Flags: +eglot +peek

M-x vscode

This module integrates language servers into Doom Emacs. They provide features you’d expect from IDEs, like code completion, realtime linting, language-aware imenu/xref integration, jump-to-definition/references support, and more.

As of this writing, this is the state of LSP support in Doom Emacs:

Module Major modes Default language server
:lang cc c-mode, c++-mode, objc-mode ccls, clangd
:lang clojure clojure-mode clojure-lsp
:lang csharp csharp-mode omnisharp
:lang elixir elixir-mode elixir-ls
:lang fsharp fsharp-mode Mono, .NET core
:lang go go-mode go-langserver
:lang haskell haskell-mode haskell-language-server
:lang java java-mode lsp-java
:lang javascript js2-mode, rjsx-mode, typescript-mode ts-ls, deno-ls
:lang julia julia-mode LanguageServer.jl
:lang ocaml tuareg-mode ocaml-language-server
:lang php php-mode php-language-server
:lang purescript purescript-mode purescript-language-server
:lang python python-mode lsp-python-ms
:lang ruby ruby-mode solargraph
:lang rust rust-mode rls
:lang scala scala-mode metals
:lang sh sh-mode bash-language-server
:lang swift swift-mode sourcekit
:lang web web-mode, css-mode, scss-mode, sass-mode, less-css-mode vscode-css-languageserver-bin, vscode-html-languageserver-bin
:lang zig zig-mode zls

7.12.12. magit

Flags: +forge

Wield git like a wizard

This module provides Magit, an interface to the Git version control system.

7.12.13. make

The discount build system

This module adds commands for executing Makefile targets.

7.12.14. pass

Flags: +auth

A password manager for nerds

This module provides an Emacs interface to Pass.

7.12.15. pdf

Emacs, your next PDF reader

This module improves support for reading and interacting with PDF files in Emacs.

It uses pdf-tools, which is a replacement for the built-in doc-view-mode for PDF files. The key difference being pages are not pre-rendered, but instead rendered on-demand and stored in memory; a much faster approach, especially for larger PDFs.

Displaying PDF files is just one function of pdf-tools. See its project website for details and videos.

7.12.16. prodigy

No sweatshop is complete without child processes

This module provides an interface for managing external services from within Emacs.

7.12.17. rgb

Creating color strings

Highlights color hex values and names with the color itself, and provides tools to easily modify color values or formats.

7.12.18. taskrunner

Taskrunner for all your projects

This module integrates taskrunner into Doom Emacs, which scraps runnable tasks from build systems like make, gradle, npm and the like.

7.12.19. terraform

Infrastructure as code

This module adds support for working with Terraform files within Emacs. This includes syntax highlighting, intelligent code completion, and the ability to run Terraform commands directly from Emacs.

7.12.20. tmux

From one multiplexer to another

This module provides an API for talking to Tmux sessions.

7.12.21. upload

Map local directories to remotes via ssh/ftp

Uses ssh-deploy to map a local folder to a remote one.

From the ssh-deploy README:

The ssh-deploy plug-in for Emacs makes it possible to effortlessly deploy local files and directories to remote hosts via Tramp (including but not limited to SSH, SFTP, FTP). It tries to provide functions that can be easily used by custom scripts.

The idea for this plug-in was to mimic the behavior of PhpStorm deployment functionality.

7.13. :ui

For modules concerned with changing Emacs’ appearance or providing interfaces for its features, like sidebars, tabs, or fonts.

7.13.1. deft

Notational velocity for Emacs

Deft is a major mode for creating, browsing, and filtering notes written in plain text formats, such as org-mode, markdown, and LaTeX. It enables you to quickly jot down thoughts and easily retrieve them later.

7.13.2. doom

Make Doom fabulous again

This module gives Doom its signature look: powered by the doom-one theme (loosely inspired by Atom’s One Dark theme) and solaire-mode. Includes:

  • A custom folded-region indicator for hideshow.
  • “Thin bar” fringe bitmaps for git-gutter-fringe.
  • File-visiting buffers are slightly brighter (thanks to solaire-mode).

7.13.3. doom-dashboard

Welcome to your doom

This module adds a minimalistic, Atom-inspired dashboard to Emacs.

Besides eye candy, the dashboard serves two other purposes:

  1. To improve Doom’s startup times (the dashboard is lighter than the scratch buffer in many cases).
  2. And to preserve the “last open directory” you were in. Occasionally, I kill the last buffer in my project and I end up who-knows-where (in the working directory of another buffer/project). It can take some work to find my way back to where I was. Not with the Dashboard.

    Since the dashboard cannot be killed, and it remembers the working directory of the last open buffer, M-x find-file will work from the directory I expect.

7.13.4. doom-quit

One does not simply quit Emacs

A silly module that throws cute confirmation prompts at you when you exit Emacs, like DOOM (the game) did. Some quotes are from the classic games, others are random, nerdy references that no decent human being has any business recognizing.

7.13.5. emoji

Flags: +ascii +github +unicode


This module gives Emacs the ability to display and insert emojis (ASCII, Github style, or unicode styles), as well as convert certain text patterns (e.g. :smile:) into emojis.

7.13.6. hl-todo


This module adds syntax highlighting for various tags in code comments, such as TODO, FIXME, and NOTE, among others.

7.13.7. hydra

Discount modality for mythological beast hunters

This module adds hydra to Doom Emacs, as well as a few custom built hydras to start with:

  • A hydra to control windows +hydra/window-nav/body.
  • A hydra to control text zoom level +hydra/text-zoom/body.

7.13.8. indent-guides

Line up them indent columns

\(No description yet\)

7.13.9. ligatures

Flags: +extra

Distract folks from your code

This module enables ligatures and arbitrary symbol substitutions with mac-auto-operator-composition-mode (on supported macOS systems) or composition tables (harfbuzz on Emacs 28), falling back on prettify-symbols-mode otherwise.

7.13.10. minimap

A map for lost programmers

This module displays a minimap of the buffer in a sidebar, similar to the feature found in many other editors.

7.13.11. modeline

Flags: +light

Snazzy, Atom-inspired modeline, plus API

This module provides an Atom-inspired, minimalistic modeline for Doom Emacs, powered by the doom-modeline package (where you can find screenshots).

7.13.12. nav-flash

Blink after big motions

This module flashes the line around the cursor after any significant motion, to make it easy to follow after big operations.

Tremendously helpful on large, 1600p+ or 4K displays.

7.13.13. neotree

NERDTree for evil nerds

This module brings a side panel for browsing project files, inspired by vim’s NERDTree.

Sure, there’s dired and projectile, but sometimes I’d like a bird’s eye view of a project.

7.13.14. ophints

An indicator for “what did I just do?”

This module provides op-hints (operation hinting), i.e. visual feedback for certain operations. It highlights regions of text that the last operation (like yank) acted on.

Uses evil-goggles for evil users and volatile-highlights otherwise.

7.13.15. popup

Flags: +all +defaults

Tame sudden yet inevitable temporary windows

This module provides a customizable popup window management system.

Not all windows are created equally. Some are less important. Some I want gone once they have served their purpose, like code output or a help buffer. Others I want to stick around, like a scratch buffer or org-capture popup.

More than that, popups ought to be the second class citizens of my editor; spawned off to the side, discarded with the push of a button (e.g. ESC or C-g), and easily restored if I want to see them again. Of course, this system should clean up after itself and kill off buffers I mark as transient.

7.13.16. tabs

Keep tabs on your buffers, literally

This module adds an Atom-esque tab bar to the Emacs UI.

7.13.17. treemacs

Flags: +lsp

A project drawer like neotree but cooler

Treemacs is a file and project explorer similar to NeoTree or vim’s NerdTree, but largely inspired by the Project Explorer in Eclipse. It shows the file system outlines of your projects in a simple tree layout allowing quick navigation and exploration, while also possessing basic file management utilities. It includes:

7.13.18. unicode

Extended unicode support for various languages

This module extends Doom’s ability to display non-English unicode. It is primarily useful for non-English Emacs users, for whom Doom’s built-in unicode support in insufficient.

This module relies on the unicode-fonts package. It tries to setup the default emacs fontset to cover as many unicode glyphs as possible by scanning all available glyphs from all available fonts.

When this module is enabled:

  • Emacs will prefer to use the doom-unicode-font font to display non-latin glyphs if it provides coverage for them.
  • The first time you run Emacs a unicode cache will be generated – this will take a while!
  • The cache will be regenerated every time Emacs is made aware of new fonts or you change the font configuration e.g. by modifying doom-unicode-font.
  • The cache will be stored and should not be regenerated unless font-related configuration or the versions of relevant packages changes.

7.13.19. vc-gutter

Get your diff out of the gutter

This module displays a diff of the current file (against HEAD) in the fringe. Supports Git, Svn, Hg, and Bzr.

7.13.20. vi-tilde-fringe

Fringe tildes beyond EOB

Displays a tilde(~) in the left fringe to indicate an empty line, similar to Vi.

7.13.21. window-select

Flags: +numbers +switch-window

Visually switch windows

This module provides several methods for selecting windows without the use of the mouse or spatial navigation (e.g. C-w {h,j,k,l}).

The command other-window is remapped to either switch-window or ace-window, depending on which backend you’ve enabled. It is bound to C-x o (and C-w C-w for evil users).

It also provides numbered windows and selection with the winum package, if desired. Evil users can jump to window N in C-w <N> (where N is a number between 0 and 9). Non evil users have C-x w <N> instead.

7.13.22. workspaces

Tab emulation, persistence, & separate workspaces

This module adds support for workspaces, powered by persp-mode, as well as a API for manipulating them.

There are many ways to use workspaces. I spawn a workspace per task. Say I’m working in the main workspace, when I realize there is a bug in another part of my project. I open a new workspace and deal with it in there. In the meantime, I need to check my email, so mu4e gets its own workspace.

Once I’ve completed the task, I close the workspace and return to main.

7.13.23. zen

Distraction-free mode for the eternally distracted

This module provides two minor modes that make Emacs into a more comfortable writing or coding environment. Folks familiar with “distraction-free” or “zen” modes from other editors – or olivetti, sublimity, and tabula-rasa (Emacs plugins) – will feel right at home.

These modes are:

Which renders (most) text in a variable pitch font (see doom-variable-pitch-font). Unlike variable-pitch-mode, this will not affect segments of text that are intended to remain in a fixed pitch font, such as code blocks or ASCII tables.
Our all-in-one “zen” mode that will:
  1. Center the current buffer.
  2. Remove superfluous UI elements (like the modeline).
  3. Activate mixed-pitch-mode.
  4. Scale up the buffer’s text slightly (see +zen-text-scale).
  5. And make the window’s borders slightly thicker (see +zen-window-divider-size).

8. Contribute

Doom is what happens when you combine incurable madness, poor naming sense, and a Factorio addiction. However, it is (mostly) the work of one guy, so there will always be gaps in its documentation, bugs lurking in dusty corners, and new features that need implementing.

If Doom has helped you, consider converting a little caffeine into a pull request, bug report, or a helpful voice in our community. Our contributor manual lists all the ways you can help and how to go about them, but don’t forget to consult our do not PR and do not bump lists before you do.

8.1. TODO How can I help?

Now that you have some caffeine set aside to convert into a contribution, what do you do? Here are a few suggestions:

  • Report bugs
  • Suggest enhancements
  • Contribute code or documentation
    • Our issue tracker has many open issues.
    • Our backlog has many tasks that are left undone due to lack of time and shifting priorities; they are free to be claimed.
    • Issues tagged good first issue have a lower barrier of entry and are good for begineers.
    • Issues tagged help wanted are issues I can’t tackle myself, and need outside help to resolve.
    • Our development roadmap outlines the project’s status, progress, and plans.
    • Our packages under review outlines the packages being considering for inclusion (or removal) from Doom. An approved package that isn’t being worked on is fair game for contributors.
    • Our upstream bugs board lists known issues with external causes. Help us address these at the source.
  • Helping out in the community
    • Helping out with issue triage
    • As a module maintainer
    • Answering questions on Discord/Discourse
    • Or just being around
  • Supporting the project

That said, before you contribute, please consult our Do not PR and Do not bump lists below (and often; they change from time to time).

8.1.1. Do not PR

Last updated 2021-10-16

There are contributions that will be immediately refused, either due to project policy or an external factor blocking development. A list of these is maintained here and is likely to change from time to time. Consult it each time you prepare to file a pull request.

  • Feature-gate keybinds in the :config default module. That is to say, PRs to wrap keybinds in (:when (featurep! ...) ...) checks will not be accepted. I explain why in this issue.
  • Directly modify modules/ this file is automatically generated by doom make module-index and should not be modified by hand.
  • Add questions to docs/ without prior approval. Selecting questions for the FAQ requires the insight of our maintainer and community leaders. Please discuss it with them beforehand.
  • Correct less than 5 non-technical spelling and grammar errors. These are popular, especially during Hacktoberfest, but their value don’t justify the time cost of reviewing them all so a minimum of 5 errors is required to be accepted. Otherwise, we’d prefer you ping us on Discord or simply wait until it is discovered by a maintainer (or a user with enough errors to correct).

    Of course, any correction that impacts the technical correctness of our documentation is exempt from this rule. e.g. Misspelling the name of a package in a shell command.

8.1.2. Do not bump

Last updated 2021-10-16

These are packages whose pins should not be updated:

  • format-all: a rewrite of the :editor format module is in the works and updates upstream have introduced breaking changes to the package that are incompatible with our module (and go again our design goals for the module).

8.2. TODO Reporting issues

You’ve found a problem and you’re ready to fire off that bug report. Our Troubleshooting guide can help you figure it out, but if that doesn’t pan out, then it is time to file a bug report.

Please do not file or answer Doom Emacs issues on Reddit, Twitter, or StackOverflow. Kindly refer them to this section.

Questions posted on other platforms are difficult to track, difficult for posterity to find, and rarely include enough information to investigate.

8.2.1. TODO Before you create that report

An effective bug report is informative. Please try to provide:

  • A backtrace of all mentioned errors.
  • A step-by-step reproduction of the issue.
  • Information about your Doom config and system environment.
  • Screenshots/casts of the issue (if possible).

This section will show you how to collect this information.

8.2.2. TODO How to write a good bug report

8.3. TODO Reporting outdated packages

Doom pins all its packages to reduce the likelihood of upstream breakage leaking into Doom Emacs. However, we may miss when a package releases hotfixes for critical issues. Let us know or PR a bump to our pinned packages.

8.4. TODO Suggesting enhancements

8.4.1. TODO Before you submit your suggestion

8.4.2. TODO How to write an effective suggestion

8.5. TODO Contributing code

There’s much to be done around here! We need bugfixes, new features, and documentation. If you’d like to convert some caffeine into Emacs Lisp, here are a few considerations before starting that PR:

  • Make sure your contribution isn’t in our Do Not PR list
  • Read our code style guide and conventions.

There are contributions that will be immediately refused, either due to project policy or an external factor blocking development in that area. A list of these kinds of contributions is maintained in two separate lists we call our do-not-PR lists.

They are: one below, which lists our do-not-PRs motivated by project policy, and one on our Discourse, which are blocked by external factors.

8.5.1. TODO Your first code contribution

8.5.2. TODO Submitting pull requests

  1. Now you wait for a code review:
    • If your PR is approved, you don’t need to do anything. It will be merged soon (the maintainer approves PRs ahead of time, then merges them in bulk later).
    • Your PR may acquire one of these labels:
      • status:needs-work: I’m interested in your PR, but it needs some changes to be accepted. Keep in mind there may be a delay between getting this tag and getting an explanation for it.
      • status:moved: the PR won’t be merged because it will be addressed elsewhere, in another PR or a future commit.
  2. The PR is either merged or closed.

8.5.3. TODO Contributing to Doom core

8.5.4. TODO Contributing to an existing module

8.5.5. TODO Contributing a new module

8.6. TODO Contributing documentation

Doom Emacs’ documentation is an ongoing effort. If you have suggestions, improvements, tutorials and/or articles to submit, don’t hesitate to get in contact via our Discord server or email. I appreciate any help I can get!

8.6.1. TODO Correcting or reporting mistakes

8.6.2. TODO Contributing to Doom’s manual

8.6.3. TODO Contributing module documentation

8.7. TODO Participate in the community

8.8. TODO Become a community moderator

8.8.1. TODO Policies

8.8.2. TODO Triage

8.8.3. TODO Labeling

8.8.4. TODO Merging

For collaborators with PR merge permissions have three options when merging commits on the Github UI: a conventional merging, squashing, or rebasing. When do you do which?

  • If a PR has one commit:
    • Squash it if the commit message needs correcting.
    • Rebase it otherwise.
  • If a PR has multiple commits:
    • Squash it if extra commits are corrective and/or add no value to the PR’s git history.
    • Merge it conventionally otherwise (don’t forget to substitute s/^Merge /merge: /).
  • If the PR has merge conflicts, ask OP to rebase or redo their PR.

8.9. TODO Become a module maintainer

8.10. TODO Support the project

Consider becoming a Github Sponsor (there are perks!) or buying @hlissner a drink on LiberaPay or Paypal. Every little bit helps Henrik allocate more time to Doom, Emacs, and his open-source capers.

9. Thank you

In the beginning Doom was just some dude’s Emacs config, then a wild userbase appeared. Little of this would be possible (or nearly as fun) without Emacs, its ecosystem of plugin developers, and you, its users. Thank you!


Check out our achievements page nifty contributor and sponsor stats!