Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upFAQ
Table of Contents
Common Questions
Does Doom work on Windows?
As a Linux/MacOS user, I have limited access to the Windows platform. Doom hasn’t been tested nor designed for it, so your mileage will vary. Some have reported success, however.
If you’ve got Doom working on Windows, let me know about it! I’d be happy to include Windows support.
How does Doom compare to Spacemacs?
To paraphrase a reddit answer to this question by gilbertw1:
- Doom is lighter than Spacemacs. Expect faster startup times and a snappier experience.
- Doom is much more opinionated than Spacemacs. It is the work of one developer, and it is catered to his eccentric taste. You can expect a more curated experience from Doom at the cost of flexibility.
- Doom is thinner than Spacemacs. There’s less between you and vanilla Emacs, which means less complexity to wrap your head around if you want to modify and customize Doom.
- Doom lacks the sheer manpower available to Spacemacs. Bugs stick around longer, documentation stays light and development is at the mercy of it’s maintainer’s schedule.
- Doom is not beginner friendly. Spacemacs works out of the box. Your mileage may vary with Doom, where bugs may creep in undetected from upstream (or plugins), my workflows may conflict with yours and things I haven’t anticipated may go wrong. To get the most out of Doom, you should be comfortable with Emacs Lisp, git and the command line.
Why such a complicated package management system?
- Scriptability: I live in the command line. I want an externally scriptable interface for updating and installing Emacs packages.
- Flexibility: I want packages from sources other than ELPA (like github). Some plugins are out-of-date through official channels, have changed hands, have a superior fork, or simply aren’t in any ELPA repo.
- Stability: I used Cask before this. It would error out with cyrptic errors depending on the version of Emacs I used and the alignment of the planets. No more.
- Performance: this system is lazy-loaded (more so if you byte-compile). Not having to initialize package.el or quelpa (and check that your packages are installed) every time you start up or load a package speeds things up.
- Seperation of concerns: I want package management and configuration to be separate. It makes it easier to grok modules and their dependencies.
- Simplicity: no external dependencies (unless you count make).
How do I start customizing Doom?
The Customization page will help you set up your private module.
How is Doom’s startup so fast?
I frequently restart Emacs and I don’t use the daemon, so startup times are important to me. Doom employs a number of techniques to make Emacs startup as zippy as can be, a lot of it is premature optimization. Here, I will describe the more effective techniques:
- Avoid garbage collection during startup. The GC eats up quite a bit of time,
easily doubling startup time. The trick is to turn up the memory threshold to
prevent it from running:
(setq gc-cons-threshold 402653184 gc-cons-percentage 0.6) ;; ... your whole emacs config here ... ;; Then reset it as late as possible; these are the reasonable defaults I use. (add-hook! 'emacs-startup-hook (setq gc-cons-threshold 16777216 gc-cons-percentage 0.1))
Don’t forget to reset these variables to some reasonable default after startup! A large gc-cons-threshold will cause freezing and stuttering during long-term interactive use.
- Like we did with the garbage collector, unset
file-name-handler-alisttoo (temporarily). Every file opened and loaded by Emacs will run through this list to check for a proper handler for the file, but during startup, it won’t need any of them. Doom doesn’t, at least.(defvar doom--file-name-handler-alist file-name-handler-alist) (setq file-name-handler-alist nil) ;; ... your whole emacs config here ... (add-hook! 'emacs-startup-hook (setq file-name-handler-alist doom--file-name-handler-alist))
- Cut down on
load-pathlookups. Eachloadandrequire(without an absolute path) costs an O(n) lookup onload-path. My Doom config has over 260 entries in its load-path, so that’s a worst case of n=260 on every lookup.There is little you can do about this, at large, but Doom tries.
- Where possible,
load-pathis let-bound to a smaller subset of itself. For example, in the doom-initialize function. - Module files are loaded with Doom’s
load!macro, which does simple string concatenation (and file checking) to build an absolute path. If byte-compiled, you also avoid that too. Altogether avoiding theload-pathlookup.
- Where possible,
- Package.el initialization is expensive, so disable it! package.el is sneaky
though, it will initialize itself if you’re not careful. Not on my watch,
criminal scum!
(setq package-enable-at-startup nil ; don't auto-initialize! ;; don't add that `custom-set-variables' block to my initl! package--init-file-ensured t)
Be warned! Without package.el initialization, you mainly lose two things:
- Emacs won’t load your packages’ autoloads files. This may be distastrous to
some especially silly geese, but not to Doom. Doom defines its own with
use-package. - Your
load-pathwill be empty, so you have to populate it manually. Doom does this in ~doom-initialize-load-path~.
- Emacs won’t load your packages’ autoloads files. This may be distastrous to
some especially silly geese, but not to Doom. Doom defines its own with
- Lazy load everything. This is a well known technique.
use-packagehelps you defer packages, and Doom defers as many as possible. It also goes the extra mile to lazy-load packages that are very difficult to lazy-load, like Company or Helm.(def-package! smart-forward :commands (smart-up smart-down smart-backward smart-forward))Note:
def-package!is simply a thin wrapper arounduse-package. - Exploit byte-compilation! Many expensive things are cached (or cut out
altogether) at compile time with the help of Emacs’
eval-when-compilemacro, which replaces a bunch of forms with its result in the byte-compiled result.Some good candidates for caching (or omitting) are the
load-path, package checks (Doom does this for core packages),exec-path(exec-path-from-shellis expensive, but a necessity for MacOS users), and so on.(setq load-path (eval-when-compile (doom-initialize t) (doom-initialize-load-path t))
Running
make compile-corebuys me a \~40% improvement in startup times. You can also byte-compile the entire config withmake compile, but this takes much longer and yields significantly diminished returns. - Use lexical-binding everywhere. Add
;; -*- lexical-binding: t; -*-to the top of your elisp files. This can break code if you’ve written it to depend on dynamic variables, but I’ve written Doom not to. - Avoid lambdas, if you can. Prefer
cl-loopanddolistovermapcormapcar. Lambdas add a little overhead each time they’re executed in loops (and the byte-compiler has trouble inlining them; especially when lexical-binding is on!). This is definitely premature optimization :P
That’s not everything, but those are the most important. Here are two articles that may shed some light on these decisions.
Troubleshooting
What’s wrong with my icons?
Many of Doom’s UI modules use the all-the-icons plugin, which uses special
fonts to display icons. These fonts must be installed for them to work properly,
otherwise you’ll get a bunch of squares and mismatched icons.
Run M-x all-the-icons-install-fonts to install them.
I’m getting “certificate validation failed” or “peculiar error” messages
If you’re a MacOS user, you need to install emacs with the --with-gnutls
option.
Otherwise, you can try setting (setq gnutls-verify-error nil), but this
disables TLS verification. Whether this is an acceptable compromise or not is up
to you.
If you are receiving these issues while trying to run a make command, you can
set the INSECURE environment variable. e.g. INSECURE=1 make install.
I’ve been unable to track down this issue, so these workarounds are your only option for now.
How do I…?
Remove Vim/Evil for a more vanilla Emacs experience?
You must do three things:
- Remove
:feature evilfrom init.el, - Run
maketo clean up lingering dependencies and refresh yuor autoloads file. - Assign a new
doom-leader-keyanddoom-localleader-key. By default, these are bound toSPCandSPC m, which will break the space key in vanilla Emacs.
Note that evil-specific configuration and keybindings (defined with map!) will
be ignored without feature/evil present (and stripped out when
byte-compiling).
Unfortunately, since Doom was designed by a vimmer, for vimmers, I’ve put little consideration into a keybinding scheme for vanilla Emacs users.