A retrospective on “setup”

Saturday, 7 February 2026

It is about five years ago that I submitted a package called setup to GNU ELPA1. The premise was simple, I had grown dissatisfied with use-package and wanted to implement my own “configuration macro” that would be a better fit for packages written in a good style.

In this post I’d like to look back on the package and the macro, to chronicle my experience and the lessons I took away.

Issues with use-package

Among people who like Emacs, especially those who avoid learning to use Emacs by configuring it, it is popular to recommend use-package when configuring Emacs. The idea is that you can avoid a lot of repetitive idiosyncrasies by instead having a macro translate a declarative-esque DSL into the right code. It also allows the user to request that a package be installed at startup if it hasn’t yet been installed.

It was written by the renowned John Wiegley around the early 2010’s — which is important because the context of the time is an important influence on the features it implements: Keywords like :autoload, :mode :interpreter or :magic are not necessary if working with Emacs packages that have properly configured autoloads and use these to adjust variables like auto-mode-alist. I also assume that the default behaviour, not to install packages, goes back to this.

Totalling at around 3500 lines of Elisp it is also not trivial to keep an overview of the code, and in my opinion it is also more tricky to extend with new keywords — at least compared to the ease at which you can define a new command.

Finally, something I never managed to figure out how to reasonably have a consistent configuration that would also use use-package for built-in, non-packages. You can add these kinds of configurations to the pseudo-package emacs, but that felt like a kludge to me.

Idea of setup

Superficially the syntax of setup is different but not a radical departure from the use-package approach. Instead of using keywords like

(use-package flymake
  :bind ("M-n" . flymake-goto-next-error))

you would use a “local” macro, bound at compile-time around the setup form

(setup flymake
  (:bind "M-n" flymake-goto-next-error))

Note that the fact that the function symbol is a keyword is in no way significant. We could have also used &bind.

There were a few ideas and goals underlying the design:

Here are a few examples from my init.el that I consider to demonstrate that applying these principles results in easy to read and write code:

(setup (:package writegood-mode)
  (:hook-into text-mode))

(setup (:package do-at-point)
  (:bind-to "C-'"))
  
;; slightly simplified
(setup (:and (executable-find "go")
             (:if-package go-mode))
  (setopt gofmt-command "goimports"
          gofmt-show-errors nil)
  (:local-hook before-save-hook gofmt)
  (:local-set compile-command "go build && go tool vet"
              tab-width 4)
  (:hook subword-mode))

For further details on the macro, I would recommend going to the EmacsWiki page linked above. The technical details are not of primary interest in this post.

A History of setup

Here I’d like to list a few events and comments in roughly chronological order:

The future of setup

I have to admit I am not as enthusiastic about the macro as I was 2021. It is not that I dislike it, the implementation still seems good and I enjoy reading it, but I am mostly indifferent about the need for configuration macros in general.

Over the last two years I have configured Emacs from start on two work machines, and both times I was more than just fine to append stuff to my init.el and use Easy Customization Interface. At the same time I continue to use setup on my personal machine, and as I grow ever more convinced of the fact that (obsessive) configuring of Emacs is a sign of a fatal misunderstanding of Emacs on some level, I don’t have the motivation to rewrite it because I don’t really have anything to gain from it. Most of the times I touch my init.el is to bind a new command, set a new user option or in the best case delete some code if an analogous feature has been upstreamed.

I don’t really know who uses setup anymore, but I am aware of people who have used it in the past and given up. Interesting nobody points me to a specific reason or issue, but my impression is that most people run into a similar kind of lethargic apathy, but decide to jump to something else instead (again, since the upstreaming of use-package I myself have considered switching a few times to simplify my configuration, but never gone through with it).

Finally, I recently suggested replacing the idea of setup macros with a more non-Lisp’ish configuration syntax, and explained why in the aforelinked article. I haven’t continued developing the proposal, though I still think it is more user friendly to someone who prefers to think of configuring Emacs not as programming with a understanding of what is going on but as toggling the right knobs to get the intended behaviour.

So the future is certain and reliable that the macro will stick around, and I guess I’ll keep on maintaining it?


  1. Actually I had first tried to add it to MELPA a year before, but it got rejected.↩︎

  2. Note that setting use-package-expand-minimally can help here↩︎