docs: discourage after! and use-package! use

There's little reason for users to use these macros in their private
configs over plain ol' `with-eval-after-load` and `use-package`, unless
they're writing their own modules.

It's my fault for signal boosting them in documentation and whenever I'm
asked for help, because beginners now believe they are somehow
required for Doom to work correctly (there are guides out there
telling beginners that migrating to Doom involves replacing all
instances of `with-eval-after-load` and `use-package` in their
pre-existing configs with `after!` and `use-package!` -- which was never
true).

What's more, I plan to replace `use-package`, internally, so the
`use-package!` macro won't exist for much longer.
This commit is contained in:
Henrik Lissner 2026-01-23 20:43:46 -05:00
parent 1a943aea69
commit 6f40ad55f5
No known key found for this signature in database
GPG key ID: B60957CA074D39A3
35 changed files with 73 additions and 74 deletions

View file

@ -497,10 +497,10 @@ launchers write a walkthrough for, you'll have better luck asking about it on
2. Remember to run ~$ doom sync~ after making [[id:594d2505-d3cb-4061-ab76-06e7c8a4e0b8][certain changes]] to your config.
Run ~$ doom help sync~ to know exactly when you should use it.
3. If you are reconfiguring a package, make sure you've deferred your settings
until the package loads with the ~after!~ macro:
until the package loads with the ~with-eval-after-load~ macro:
#+begin_src emacs-lisp
(after! magit
(with-eval-after-load 'magit
(setq magit-repository-directories '(("~/projects" . 2))
magit-save-repository-buffers nil))
#+end_src
@ -542,7 +542,7 @@ Here are a few common causes for random crashes:
E.g. To disable ~org-indent-mode~:
#+begin_src emacs-lisp
;; in $DOOMDIR/config.el
(after! org
(with-eval-after-load 'org
(setq org-startup-indented nil))
#+end_src

View file

@ -77,7 +77,7 @@ Use ~set-irc-server! SERVER PLIST~ to configure IRC servers. Its second argument
(a plist) takes the same arguments as ~circe-network-options~:
#+begin_src emacs-lisp
;; if you omit =:host=, ~SERVER~ will be used instead.
(after! circe
(with-eval-after-load 'circe
(set-irc-server! "irc.libera.chat"
`(:tls t
:port 6697
@ -94,7 +94,7 @@ macos or :tools pass modules if you want integration into the MacOS keychain or
[[https://www.passwordstore.org/][Pass]]):
#+begin_src emacs-lisp
;;; in $DOOMDIR/config.el
(after! circe
(with-eval-after-load 'circe
(defun fetch-password (&rest params)
(require 'auth-source)
(if-let* ((match (car (apply #'auth-source-search params)))

View file

@ -25,10 +25,10 @@ Read RSS feeds in the comfort of Emacs.
** Hacks
- By default ~elfeed-search-filter~ is set to ~@2-weeks-ago~ and makes the last
2 weeks of entries visible. This needs to be set after elfeed has loaded like
so in your =$DOOMDIR/config.el=:
2 weeks of entries visible. This needs to be set after elfeed has loaded:
#+begin_src emacs-lisp
(after! elfeed
;;; in $DOOMDIR/config.el
(with-eval-after-load 'elfeed
(setq elfeed-search-filter "@1-month-ago +unread"))
#+end_src

View file

@ -128,7 +128,7 @@ the function ~ispell-change-dictionary~.
Adjust ~spell-fu-idle-delay~ to change how long Emacs waits to spellcheck after
recent changes:
#+begin_src emacs-lisp
(after! spell-fu
(with-eval-after-load 'spell-fu
(setq spell-fu-idle-delay 0.5)) ; default is 0.25
#+end_src
@ -139,7 +139,7 @@ Lazy spellcheck is provided by [[doom-package:flyspell-lazy]] package.
recent changes (default as 1), while ~flyspell-lazy-window-idle-seconds~ sets
how many seconds until the whole window is spellchecked (default as 3):
#+begin_src emacs-lisp
(after! flyspell
(with-eval-after-load 'flyspell
(setq flyspell-lazy-idle-seconds 2))
#+end_src

View file

@ -103,21 +103,21 @@ symbol, or a list of either. BACKENDS are prepended to ~company-backends~ for
those modes.
#+begin_src emacs-lisp
(after! js2-mode
(with-eval-after-load 'js2-mode
(set-company-backend! 'js2-mode 'company-tide 'company-yasnippet))
(after! sh-script
(with-eval-after-load 'sh-script
(set-company-backend! 'sh-mode
'(company-shell :with company-yasnippet)))
(after! cc-mode
(with-eval-after-load 'cc-mode
(set-company-backend! 'c-mode
'(:separate company-irony-c-headers company-irony)))
#+end_src
To unset the backends for a particular mode, pass ~nil~ to it:
#+begin_src emacs-lisp
(after! sh-script
(with-eval-after-load 'sh-script
(set-company-backend! 'sh-mode nil))
#+end_src

View file

@ -220,7 +220,7 @@ A few variables may be set to change behavior of this module:
To disable idle (as-you-type) completion, unset ~corfu-auto~:
#+begin_src emacs-lisp
;;; in $DOOMDIR/config.el
(after! corfu
(with-eval-after-load 'corfu-auto
(setq corfu-auto nil))
#+end_src

View file

@ -176,7 +176,7 @@ framework other than helm, say company, may break if handed off to Helm, so it
makes sense to exempt ~foo~ with the following:
#+begin_src emacs-lisp
;; add to $DOOMDIR/config.el
(after! helm
(with-eval-after-load 'helm
(add-to-list 'helm-completing-read-handlers-alist (cons #'foo nil)))
#+end_src
@ -187,7 +187,7 @@ maintain consistency with other icons across Doom's modules,
[[doom-package:nerd-icons]] is used. To change this:
#+begin_src emacs-lisp
;; add to $DOOMDIR/config.el
(after! helm
(with-eval-after-load 'helm
(setq helm-icons-provider 'treemacs))
#+end_src

View file

@ -188,7 +188,7 @@ disabled completely. Doom lowers the default value to prevent performance
issues, so increasing the value may fix your issue:
#+begin_src elisp
;;; add to $DOOMDIR/config.el
(after! ivy
(with-eval-after-load 'ivy
(setq ivy-sort-max-size 30000)) ; Doom sets this to 7500, but Ivy's default is 30k
#+end_src

View file

@ -83,7 +83,7 @@ Doom, you will need to ensure that the call in your config is contained within
an =after!= form, eg below to override Clojure's with =zprint=:
#+begin_src emacs-lisp
(after! clojure-mode
(with-eval-after-load 'clojure-mode
(set-formatter! 'zprint '("zprint" "-") :modes '(clojure-mode)))
#+end_src
@ -141,16 +141,16 @@ Here are some ways to use them:
(setq-hook! 'emacs-lisp-mode-hook +format-inhibit t)
;; To permenantly disable a formatter:
(after! csharp-mode
(with-eval-after-load 'csharp-mode
(set-formatter! 'csharpier nil))
;; To define new formatters:
;; From modules/tools/docker/config.el:
(after! dockerfile-mode
(with-eval-after-load 'dockerfile-mode
(set-formatter! 'dockfmt '("dockfmt" "fmt" filepath) :modes '(dockerfile-mode)))
;; From modules/lang/sh/config.el:
(after! sh-script
(with-eval-after-load 'sh-script
(set-formatter! 'shfmt '("shfmt" "-ci"
(unless indent-tabs-mode
(list "-i" (number-to-string tab-width))))))

View file

@ -48,7 +48,7 @@ through them.
To enable a set of items to cycle through globally:
#+begin_src emacs-lisp
;; in $DOOMDIR/config.el
(after! rotate-text
(with-eval-after-load 'rotate-text
(add-to-list 'rotate-text-words '("small" "medium" "large")))
#+end_src
@ -56,7 +56,7 @@ To add a sequence to a specific mode:
#+begin_src emacs-lisp
;; in $DOOMDIR/config.el
(set-rotate-patterns! 'c++-mode
:words '(("float" "double")))
:words '(("float" "double")))
#+end_src
When configuring a sequence of words or symbols that should be rotated through,

View file

@ -151,7 +151,7 @@ Use the following syntax to configure the entries displayed in
#+begin_src emacs-lisp
;;; add to $DOOMDIR/config.el
(after! dirvish
(with-eval-after-load 'dirvish
(setq! dirvish-quick-access-entries
`(("h" "~/" "Home")
("e" ,user-emacs-directory "Emacs user directory")

View file

@ -57,7 +57,7 @@ persist across Emacs sessions.
** Disabling persistent undo history
- If you are using [[doom-module:+tree]]:
#+begin_src emacs-lisp
(after! undo-tree
(with-eval-after-load 'undo-tree
(setq undo-tree-auto-save-history nil))
#+end_src

View file

@ -85,7 +85,7 @@ as =msmtp= (recommended).
If you use =msmtp=:
#+begin_src emacs-lisp
;; add to $DOOMDIR/config.el
(after! mu4e
(with-eval-after-load 'mu4e
(setq sendmail-program (executable-find "msmtp")
send-mail-function #'smtpmail-send-it
message-sendmail-f-is-evil t
@ -164,7 +164,7 @@ If this is of interest, this approach can be seen [[https://tecosaur.github.io/e
Mu4e can be configured to call an arbitary shell command to fetch your email. To
use it, set [[var:mu4e-get-mail-command]]:
#+begin_src emacs-lisp
(after! mu4e
(with-eval-after-load 'mu4e
(setq mu4e-get-mail-command "your_command"))
#+end_src

View file

@ -153,7 +153,7 @@ own backend:
It is possible to change the =*notmuch-hello*= buffer if you want to.
#+begin_src emacs-lisp
;; add to $DOOMDIR/config.el
(after! notmuch
(with-eval-after-load 'notmuch
(setq notmuch-show-log nil
notmuch-hello-sections `(notmuch-hello-insert-saved-searches
notmuch-hello-insert-alltags)
@ -189,7 +189,7 @@ you're used to sending, so here's some example configuration that turns those
features off:
#+begin_src emacs-lisp
;; add to $DOOMDIR/config.el
(after! org-mime
(with-eval-after-load 'org-mime
(setq org-mime-export-options '(:section-numbers nil
:with-author nil
:with-toc nil)))

View file

@ -166,7 +166,7 @@ Search for your combination of =(LSP client package, LSP server)=. You are using
*** LSP-mode with clangd
#+begin_src emacs-lisp
;;; add to $DOOMDIR/config.el
(after! lsp-clangd
(with-eval-after-load 'lsp-clangd
(setq lsp-clients-clangd-args
'("-j=3"
"--background-index"
@ -183,7 +183,7 @@ server everywhere clangd can be used.
*** LSP-mode with ccls
#+begin_src emacs-lisp
;;; add to $DOOMDIR/config.el
(after! ccls
(with-eval-after-load 'ccls
(setq ccls-initialization-options '(:index (:comments 2) :completion (:detailedLabel t)))
(set-lsp-priority! 'ccls 1))
#+end_src
@ -198,7 +198,7 @@ and =:json-null= for ~null~).
command, use [[fn:set-eglot-client!]]:
#+begin_src emacs-lisp
;;; add to $DOOMDIR/config.el
(after! cc-mode
(with-eval-after-load 'cc-mode
(set-eglot-client! 'cc-mode '("clangd" "-j=3" "--clang-tidy")))
#+end_src
@ -207,7 +207,7 @@ command, use [[fn:set-eglot-client!]]:
use [[fn:set-eglot-client!]]:
#+begin_src emacs-lisp
;;; add to $DOOMDIR/config.el
(after! cc-mode
(with-eval-after-load 'cc-mode
(set-eglot-client! 'cc-mode '("ccls" "--init={\"index\": {\"threads\": 3}}")))
#+end_src

View file

@ -116,7 +116,7 @@ See below for advanced configuration.
If you want different arguments to be passed to =fprettier=, follow this example:
#+begin_src emacs-lisp
(after! f90
(with-eval-after-load 'f90
(set-formatter! 'fprettify '("fprettify" "--enable-decl" "-w" "4" "-") :modes '(f90-mode fortran-mode)))
#+end_src

View file

@ -85,7 +85,7 @@ After installing your preferred formatter, make sure to set
Make sure to configure the lsp to use your perfered formatter, e.g.:
#+begin_src emacs-lisp
;; ~/.doom.d/config.el
(after! lsp-haskell
(with-eval-after-load 'lsp-haskell
(setq lsp-haskell-formatting-provider "brittany"))
#+end_src

View file

@ -55,7 +55,7 @@ To get this working, simply set [[var:idris-interpreter-path]] to the path of th
=idris2= executable. E.g.
#+begin_src emacs-lisp
;;; add to $DOODMIR/config.el
(after! idris-mode
(with-eval-after-load 'idris-mode
(setq idris-interpreter-path "idris2"))
#+end_src

View file

@ -79,7 +79,7 @@ environment in which it is installed. This is set to v1.6 by default as it is
the current LTS:
#+begin_src emacs-lisp
;; in $DOOMDIR/config.el
(after! lsp-julia
(with-eval-after-load 'lsp-julia
(setq lsp-julia-default-environment "~/.julia/environments/v1.6"))
#+end_src
@ -96,7 +96,7 @@ But to let [[doom-package:eglot-jl]] use the environment bundled with it, set it
~eglot-jl-base~ instead:
#+begin_src emacs-lisp
;; in $DOOMDIR/config.el
(after! eglot-jl
(with-eval-after-load 'eglot-jl
(setq eglot-jl-language-server-project eglot-jl-base))
#+end_src
@ -133,7 +133,7 @@ described above.
v1.6 by default as it is the current LTS:
#+begin_src emacs-lisp
;; in $DOOMDIR/config.el
(after! lsp-julia
(with-eval-after-load 'lsp-julia
(setq lsp-julia-default-environment "~/.julia/environments/v1.6"))
#+end_src

View file

@ -161,7 +161,7 @@ https://www.mfoot.com/blog/2015/11/22/literate-emacs-configuration-with-org-mode
rather than cycle through it recursively. This can be reversed with:
#+begin_src emacs-lisp
(after! evil-org
(with-eval-after-load 'evil-org
(remove-hook 'org-tab-first-hook #'+org-cycle-only-current-subtree-h))
#+end_src
- (Evil users) Nearby tables are formatted when exiting insert or replace mode

View file

@ -108,12 +108,12 @@ To prioritize ~ty~:
;;; add to $DOOMDIR/config.el
;; for eglot users
(after! python
(with-eval-after-load 'python
(set-eglot-client! '(python-mode python-ts-mode) '("ty" "server")))
;; Not necessary for lsp-mode users, because `ty-ls' is already priority = -1
;; (lower = higher priority). Including this for posterity:
(after! python
(with-eval-after-load 'python
(set-lsp-priority! 'ty-ls -5)) ; default is -1
#+end_src
@ -122,7 +122,7 @@ Formatting is handled by the [[doom-module::editor format]] module. Python buffe
use [[https://black.readthedocs.io/en/stable/getting_started.html#installation][black]], by default. [[https://github.com/astral-sh/ruff][ruff]] is also supported:
#+begin_src elisp
;;; Add to $DOOMDIR/config.el
(after! python
(with-eval-after-load 'python
(set-formatter! 'ruff :modes '(python-mode python-ts-mode)))
#+end_src

View file

@ -66,7 +66,7 @@ Formatting is handled using the [[doom-module::editor format]] module via [[http
~parinfer~, ~lispy~. If you wish to enable it:
#+begin_src emacs-lisp
;; in $DOOMDIR/config.el
(after! racket-mode
(with-eval-after-load 'racket-mode
(add-hook 'racket-mode-hook #'racket-smart-open-bracket-mode))
#+end_src

View file

@ -67,8 +67,8 @@ In addition, this module provides support for native Org-mode citations
([[doom-package:org-cite]]).
* Configuration
To override any defaults set by this module, do so in an ~(after! package ...)~
block in =$DOOMDIR/config.el=.
To override any defaults set by this module, do so in an ~(with-eval-after-load
'package ...)~ block in =$DOOMDIR/config.el=.
** Org-cite
*** Processor configuration

View file

@ -98,7 +98,7 @@ C-x C-f /docker:$USER@$CONTAINER:/path/to/file
Thanks to [[https://github.com/magit/magit-popup][magit-popup]], all the popups default arguments can be customized. For
example, here is how to customize the arguments for =docker-image-run-popup=:
#+begin_src emacs-lisp
(after! docker
(with-eval-after-load 'docker
(setq docker-image-run-arguments '("-i" "-t" "--rm")))
#+end_src
@ -133,7 +133,7 @@ For older versions of TRAMP you can dump [[https://github.com/emacs-pe/docker-tr
~load-path~ somewhere and add the following to =$DOOMDIR/config.el= to overwrite
~tramp-wait-for-output~ with the patch applied:
#+begin_src emacs-lisp
(after! tramp
(with-eval-after-load 'tramp
(require 'docker-tramp-compat))
#+end_src

View file

@ -59,7 +59,7 @@ The ~editorconfig-indentation-alist~ variable contains a list of major modes and
their indentation variables. To add coffee-mode to it:
#+begin_src emacs-lisp
;; in $DOOMDIR/config.el
(after! editorconfig
(with-eval-after-load 'editorconfig
(add-to-list 'editorconfig-indentation-alist '(coffee-mode coffee-tab-width)))
#+end_src

View file

@ -69,8 +69,8 @@ buffer.
To use this module with only ChatGPT, you only need to set ~gptel-api-key~ to your
OpenAI key. For other LLMs you'll need to call one of the ~gptel-make-*~ functions
in an ~(after! gptel ...)~ block. Examples of these calls can be found [[https://github.com/karthink/gptel?tab=readme-ov-file#other-llm-backends][in gptel's
readme]].
in an ~(with-eval-after-load 'gptel ...)~ block. Examples of these calls can be
found [[https://github.com/karthink/gptel?tab=readme-ov-file#other-llm-backends][in gptel's readme]].
* Troubleshooting
/There are no known problems with this module./ [[doom-report:][Report one?]]

View file

@ -229,7 +229,7 @@ instead of your system browser, set ~+lookup-open-url-fn~ and/or
with Xwidgets support):
#+begin_src emacs-lisp
(setq +lookup-open-url-fn #'+lookup-xwidget-webkit-open-url-fn)
(after! dash-docs
(with-eval-after-load 'dash-docs
(setq dash-docs-browser-func #'+lookup-xwidget-webkit-open-url-fn))
#+end_src

View file

@ -62,7 +62,7 @@ If you are new to Magit, see the [[https://github.com/magit/magit#getting-starte
To enable gravatars when viewing commits:
#+begin_src emacs-lisp
;; in $DOOMDIR/config.el
(after! magit
(with-eval-after-load 'magit
(setq magit-revision-show-gravatars '("^Author: " . "^Commit: ")))
#+end_src
@ -72,7 +72,7 @@ This is so for [[https://magit.vc/manual/magit/Performance.html][performance rea
/all/ visible hunks with:
#+begin_src emacs-lisp
;; in $DOOMDIR/config.el
(after! magit
(with-eval-after-load 'magit
(setq magit-diff-refine-hunk 'all))
#+end_src

View file

@ -155,11 +155,11 @@ it:
#+begin_src elisp
;;; add to $DOOMDIR/config.el
(after! treesit
(with-eval-after-load 'treesit
(setq treesit-font-lock-level 3))
;; Alternatively, to only affect specific major modes:
(after! treesit
(with-eval-after-load 'treesit
(setq treesit-font-lock-level
'((python-ts-mode . 3)
(c-ts-mode . 2)

View file

@ -50,7 +50,7 @@ The default note format is org-mode. You can change this by setting the value of
the variable ~deft-default-extension~. Replacing the value with ~"md"~, for
example, will change the default note format to markdown:
#+begin_src emacs-lisp
(after! deft
(with-eval-after-load 'deft
(setq deft-default-extension "md"))
#+end_src

View file

@ -68,7 +68,7 @@ To add your own ITEMS you would need to configure them using
~hl-todo-keyword-faces~:
#+begin_src emacs-lisp
;; in $DOOMDIR/config.el
(after! hl-todo
(with-eval-after-load 'hl-todo
(setq hl-todo-keyword-faces
`(("FOO" . ,(face-foreground "MY COLOUR HEX CODE"))
("BAR" . ,(face-foreground 'my-colour-var)))))

View file

@ -70,14 +70,14 @@ This module requires one of three setups for ligatures to work:
If you want to set symbol replacements for modules that don't have them by
default you can use the ~set-ligatures!~ function in your config.el file
#+BEGIN_SRC emacs-lisp
(after! PACKAGE
(with-eval-after-load 'PACKAGE
(set-ligatures! 'MAJOR-MODE
:symbol "keyword"))
#+end_src
E.g.
#+begin_src emacs-lisp
(after! go-mode ; in this case the major mode and package named the same thing
(with-eval-after-load 'go-mode ; in this case the major mode and package named the same thing
(set-ligatures! 'go-mode
:def "func" ; function keyword
:true "true" :false "false"
@ -228,7 +228,7 @@ happen in all modes, you can use
#+begin_src elisp
;; Set all your custom ligatures for all prog-modes here.
;; This section is *out of* the after! block.
;; This section is *outside* the `with-eval-after-load' block.
;; Example: only get ligatures for "==" and "===" in programming modes by
;; default, and get only "www" in all buffers by default.
(set-font-ligatures! 'prog-mode :append "==" "===")

View file

@ -93,7 +93,7 @@ Some possible solutions:
1. Add some padding to the modeline definition:
#+begin_src emacs-lisp
(after! doom-modeline
(with-eval-after-load 'doom-modeline
(doom-modeline-def-modeline 'main
'(bar matches buffer-info remote-host buffer-position parrot selection-info)
'(misc-info minor-modes check input-method buffer-encoding major-mode process vcs " "))) ; <-- added padding here

View file

@ -76,22 +76,22 @@ A list of fonts with good unicode coverage can be found on the page of the
** Advanced configuration
Consult the [[https://github.com/rolandwalker/unicode-fonts][unicode-fonts]] package documentation for a description of more
advanced configuration. The configuration should be placed, as usual, in
=$DOOMDIR/config.el= wrapped in an ~(after! unicode-fonts)~ block. The variable
~unicode-fonts-blocks~ contains a list of all unicode block names and their
character ranges. The default fonts to search for glyphs are in the variable
~unicode-fonts-block-font-mapping~.
=$DOOMDIR/config.el= wrapped in an ~(with-eval-after-load 'unicode-fonts)~ block.
The variable ~unicode-fonts-blocks~ contains a list of all unicode block names and
their character ranges. The default fonts to search for glyphs are in the
variable ~unicode-fonts-block-font-mapping~.
If you want to use the font =Symbola= for =Miscellaneous Symbols= by default
use:
#+begin_src emacs-lisp
;; in $DOOMDIR/config.el
(after! unicode-fonts
(with-eval-after-load 'unicode-fonts
(push "Symbola" (cadr (assoc "Miscellaneous Symbols" unicode-fonts-block-font-mapping))))
#+end_src
If you want to redefine several blocks an efficient way would be:
#+begin_src emacs-lisp
(after! unicode-fonts
(with-eval-after-load 'unicode-fonts
(dolist (unicode-block '("Mathematical Alphanumeric Symbols"
"Mathematical Operators"
"Miscellaneous Mathematical Symbols-A"

View file

@ -44,23 +44,22 @@
;; Whenever you reconfigure a package, make sure to wrap your config in an
;; `after!' block, otherwise Doom's defaults may override your settings. E.g.
;; `with-eval-after-load' block, otherwise Doom's defaults may override your
;; settings. E.g.
;;
;; (after! PACKAGE
;; (with-eval-after-load 'PACKAGE
;; (setq x y))
;;
;; The exceptions to this rule:
;;
;; - Setting file/directory variables (like `org-directory')
;; - Setting variables which explicitly tell you to set them before their
;; package is loaded (see 'C-h v VARIABLE' to look up their documentation).
;; package is loaded (see 'C-h v VARIABLE' to look them up).
;; - Setting doom variables (which start with 'doom-' or '+').
;;
;; Here are some additional functions/macros that will help you configure Doom.
;;
;; - `load!' for loading external *.el files relative to this one
;; - `use-package!' for configuring packages
;; - `after!' for running code after a package has loaded
;; - `add-load-path!' for adding directories to the `load-path', relative to
;; this file. Emacs searches the `load-path' when you load packages with
;; `require' or `use-package'.