Open-source project
emacscollective/no-littering avatar
emacscollective/no-littering

no-littering: giving Emacs packages a predictable place to write

Help keeping ~/.config/emacs clean

711 stars81 forksEmacs LispGPL-3.0

At a glance

What is it?
no-littering is an Emacs Lisp package that themes the path variables of built-in and third-party packages so configuration lands under an etc directory and persistent data under a var directory instead of scattering across your home directory. It is GPL-3.0 licensed, configurable, and does not migrate existing files for you.
Who is it for?
no-littering fits an Emacs user whose home directory has been colonised by package files with meaningless names, and who wants one predictable location for configuration and another for data, ideally with the option to choose both. It does not fit someone who expects existing files to be moved for them, since the package explicitly leaves that to a manual or semi-automatic migration.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Emacs Lisp, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem is that every package invents its own path

Emacs packages do not agree on where to store configuration or persistent data, and the README is unusually blunt that this is not only a third-party problem but also a built-in one. Some packages write directly into user-emacs-directory, some into $HOME, some into a subdirectory of either, and some elsewhere entirely. On top of that, the file names often give no clue about which package created them, which is what makes a home directory hard to clean up. no-littering answers this by changing the values of path variables so configuration files go to no-littering-etc-directory, which defaults to etc under user-emacs-directory and therefore usually to $HOME/.config/emacs/etc, and persistent data files go to no-littering-var-directory, defaulting to var and therefore usually $HOME/.config/emacs/var. The README compares the idea to a color-theme and calls it a path-theme, which is a good description of the scope.

Load it first, or your own path settings win

The usage requirement is a single form with a single consequence: load the feature as early as possible in your init file, and make sure it happens before you change any path variables by some other method. Load order decides the outcome here, because a package that later sets a path variable with a hard-coded value will simply overwrite what no-littering did. The package is loaded with a require. If you want different base directories than the defaults, you have to set the variables before loading the feature, and the README recommends wrapping the assignments in eval-and-compile so that the values do not differ at compile time, which matters when your init file is byte-compiled:

elisp
  (eval-and-compile ; Ensure values don't differ at compile time.
    (setq no-littering-etc-directory
          (expand-file-name "config/" user-emacs-directory))
    (setq no-littering-var-directory
          (expand-file-name "data/" user-emacs-directory))
    (require 'no-littering))

The two base directories are separate on purpose, and picking them is the only configuration the package really asks of you.

Backups and auto-save stay outside until you ask

There is one deliberate gap in the theming, and the reason is security rather than tidiness. Creating backups raises the odds that secret information which would otherwise never be stored in clear text ends up on disk, and backups also raise the odds that leaked secrets persist for longer. The author of the package wants at least to ensure that using no-littering does not make that worse, so simply loading the package does not theme the built-in backup and auto-save functionality, and it does not theme the third-party undo-tree package either. A function called no-littering-theme-backups does theme those features, and the README asks you to read its docstring and implementation before calling it from your init files. If your threat model includes secrets in buffers, that is the function to read closely, not the rest of the package.

Lock files, recent files and customizations each need a small snippet

Three common sources of clutter are handled by documented snippets rather than automatically, and each has a reason to be opt-in. Lock files can be collected into a single directory by pointing lock-file-name-transforms at a subdirectory of the var directory:

elisp
  (let ((dir (no-littering-expand-var-file-name "lock-files/")))
    (make-directory dir t)
    (setq lock-file-name-transforms `((".*" ,dir t))))

Recent file lists can be kept out of the themed directories, which stops the packages own data files from crowding the recentf list:

elisp
  (require 'recentf)
  (add-to-list 'recentf-exclude
               (recentf-expand-file-name no-littering-var-directory))
  (add-to-list 'recentf-exclude
               (recentf-expand-file-name no-littering-etc-directory))

And Emacs writes customizations into init.el by default, which you can redirect to a sibling file or into the etc directory:

elisp
  (setq custom-file (expand-file-name "custom.el" user-emacs-directory))
  ;; or
  (setq custom-file (no-littering-expand-etc-file-name "custom.el"))

The naming convention is visible in that last line: a themed file is named after the variable and the package, and the no-littering-expand-etc-file-name helper does the expansion for you.

Redirecting the native compilation cache on Emacs 29

Native compilation writes its cache to a location that is easy to forget about and harder to clean, and the README gives a specific recipe for Emacs 29. The function startup-redirect-eln-cache is available only on some versions, and native-comp-available-p has to report that native compilation is actually available, so the snippet guards on both before it calls anything. The README suggests putting this in early-init.el, because the cache is used during startup and the redirection needs to happen before it is used:

elisp
  (when (and (fboundp 'startup-redirect-eln-cache)
             (fboundp 'native-comp-available-p)
             (native-comp-available-p))
    (startup-redirect-eln-cache
     (convert-standard-filename
      (expand-file-name  "var/eln-cache/" user-emacs-directory))))

The destination here is var/eln-cache under user-emacs-directory, which is where it belongs once the var directory holds the persistent data.

No automatic migration, and migrate.org explains the manual one

The package does not move your existing files to their new locations, and the README is upfront about that. The consolation is that you also do not have to do it completely by hand, because a contributed file, migrate.org, provides guidance and tools to help with the migration. That framing matters for anyone planning an adoption: the hard part of switching is not enabling the package but dealing with the files already on disk, and the README hands you a document rather than a script that silently moves things. A package that renamed or relocated files behind your back would be a different kind of risk, particularly for the backup and auto-save files discussed above, so the conservative choice here is the deliberate one. The project also says it still has a long way to go before most built-in and many third-party path variables are properly themed, and it depends on user contributions for coverage.

Conventions, a checklist and a pull request template

Because the project is a shared naming scheme, its contribution rules matter as much as its code. The README states that the conventions do not cover every edge case and are not set in stone, and that diverging is allowed if the commit message provides justification, while uncertainty about a convention should be mentioned in the pull request message so the wording can be improved. The naming rules themselves are concrete: file names are based on the name of the Emacs lisp variable and the package, the package name serves as the file name prefix unless the file sits in a subdirectory in which case the subdirectory does, the package name wins when package and variable prefix disagree, a trailing -file, -default-file, -directory or -default-directory suffix is usually dropped from the file name, and an appropriate extension is added so the file opens in the right major mode, for example .eld for an S-expression. The checklist is tracked in README.org, and since GitHub cannot tick those boxes, the options are opening the file in Emacs and pressing C-c C-c, or using an interactive checklist in a browser.

A small Makefile, a doc site and a GPL-3.0 licence

The build is a plain Makefile that includes default.mk and an optional .config.mk, with targets for the Lisp code, the documentation and the publication of the docs, and a help target that prints what each one does. The lisp target compiles the elc files, generates the autoloads and runs a check-declare pass over the directory using Emacs in batch mode, while redo rebuilds from scratch after a clean. The docs targets delegate to a subdirectory make, and the clean target removes the compiled files and the generated autoloads. On the repository side, the top-level entries are small and legible: no-littering.el, README.org, migrate.org, a Makefile, a docs directory and a .dir-locals.el file. The licence is GPL-3.0, and the release history shows regular tagged versions, with v1.9.0 on 2026-07-31, v1.9.1 on 2026-09-01 and v1.9.2 on 2026-10-01, and the last push to the repository was on 2026-10-13. Unlike many small Emacs packages, this one has a visible release rhythm.

Editorial conclusion

no-littering fits an Emacs user whose home directory has been colonised by package files with meaningless names, and who wants one predictable location for configuration and another for data, ideally with the option to choose both. It does not fit someone who expects existing files to be moved for them, since the package explicitly leaves that to a manual or semi-automatic migration. Before switching, read migrate.org, load the package before you touch any path variable yourself, and decide whether to keep backups and auto-save files inside the themed directories, which the package leaves off by default on purpose.

Frequently asked questions

What does no-littering actually change in my Emacs setup?

It changes the values of path variables so that configuration files go to no-littering-etc-directory, by default etc under user-emacs-directory, and persistent data files go to no-littering-var-directory, by default var under the same directory. The README compares the idea to a color-theme and calls it a path-theme.

How do I load no-littering in my init file?

Load it as early as possible and before you change any path variables by another method, since load order decides which value wins. To use different base directories, set no-littering-etc-directory and no-littering-var-directory before the require, wrapped in eval-and-compile so the values match at compile time.

Does no-littering move my existing files to the new locations?

No. The package does not automatically migrate existing files, and the README says you do not have to do it completely by hand either, because a contributed file, migrate.org, provides guidance and tools to help with the migration.

Does no-littering theme backup and auto-save files?

Not by default. Simply loading the package does not theme the built-in backup and auto-save functionality, nor the third-party undo-tree package, because backups raise the odds of secrets being written to disk. A separate function, no-littering-theme-backups, does theme them, and its docstring should be read before calling it.

Official sources

  1. emacscollective/no-littering on GitHub
  2. Issues
  3. License: GPL-3.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/emacscollective-no-littering.svg)](https://hysenlabs.com/projects/emacscollective-no-littering)

Was this useful?