Edited to clarify XDG_RUNTIME_DIR based on feedback from smcv.

The XDG base directory specification exists to address the problem of where programs should look for various kinds of files on a Unix system. Traditionally, in Unix, a per-program, per-user configuration file is stored as a “dot file”: program foo would expect to find a file such as $HOME/.foorc at startup, and if it doesn’t exist, read /etc/foorc. Or possibly both, and possibly more. This has led the home directories of Unix users to have tens, even hundreds of configuration files. Mine has currently 83 such files, but I pruned it brutally before the holidays. The specification specifies ways in which this mess can be reduced, as long as programs follow it.

The specification deals with four types of files:

  • configuration files
  • data files
  • files with cached data
  • small files needed at run time for interprocess communication

Configuration files affect how a program does things. The specification assumes a model where a user can override per-system defaults, and those can override defaults shipped with the program, and those in turn can override built-in, hardcoded defaults. Thus, configuration files need to be looked up in a number of places.

Data files are files that the program needs or creates. Typically, these would be data such as icons, templates, and game levels, supplied with the program, but can also be things such as cookies saved by a web browser. Documents that the user creates using the program would typically be data files in this context.

Cache data is meant to be not important. Ideally, the user can delete them at any time without anything breaking.

Runtime files for interprocess communication includes things like the sockets for the GnuPG command line tool and the GPG agent to communicate. They’re meant to exist only while the user is logged in, and should not take much disk space.

There are many other kinds of files, of course, but this is what’s in scope of the specification.

Specifying the directories

For all directories, the specification provides defaults and a way to override the default using an environment variable.

For all four types of files, there is a single directory where the program can write files of that type. For configuration and data files, there is also a list of fallback directories where it can look up files not found in its single directory.

Type of file Environment variable Default
configuration XDG_CONFIG_HOME $HOME/.config
data XDG_DATA_HOME $HOME/.local/share
cached data XDG_CACHE_HOME $HOME/.cache
runtime file XDG_RUNTIME_DIR no default
fallback config XDG_CONFIG_DIRS /etc/xdg
fallback data XDG_DATA_DIRS /usr/local/share/:/usr/share/

The usual value for XDG_RUNTIME_DIR is /run/user/$UID. The spec says that if it isn’t set, there is no default. Some software falls back to ~/.cache with a warning to the user, other software disables any features that requires the runtime directory.

is the current customary location for Linux. It’s not specified by the XDG base directory specification.

If any of the environment variables contains a directory that is not an absolute path name, that value should be ignored.

For each directory, the specification gives a base directory. Each program should put its files in a subdirectory of the base directory: program foo should use $XDG_CONFIG_DATA/foo for example.

Portability

The problem of finding files of various kinds exists across operating systems. A portable program should use an abstraction that is implemented in the correct way for each platform. The XDG specification is specific to Unix, but the concepts are portable.

I lack experience with Windows and Macintosh systems to give details of what the correct places for each type of file are on those systems. However, in my quest to find a library to implement XDG for my own use, on Unix, I might as well look for something that supports other platforms as well.

Other directories

The freedesktop.org project also defines a way to specify where certain kinds of user data goes: documents, pictures, music, etc. This is known as the xdg-user-dirs specification. Again, this is for Unix, and desktop software on free Unix systems, but the concepts are intentionally portable to other systems. This is also an important specification, but not relevant to me at this time.

Rust libraries

For a software project written in Rust that I work on with a friend, we want to support the XDG base directory specification and we would like to support it well. The specification is not very difficult to implement, but we would prefer to use an existing crate, and there are many options. This blog post is a brief evaluation of the options I found.

I searched https://crates.io/search?q=xdg to find candidates. There’s a lot of crates for this. However, some seem to be empty placeholders, which I’m not even listing.

Of these, I’m dropping the ones that are only for Unix. The various variants of “dirs” are a low-level library, and used by the “directories” variants, so I’ll concentrate on the higher level ones. Of those, the “directories-next” create seems newer than the “directories” one, so I"ll prefer that one. This leaves three:

Rubric

I’m going to evaluate the crates using the following approach: I’ll write a small program that uses the crate and writes out the paths to the four data directories. I’ll then run it with the environment variables set to various values and check that the results are as expected.

  • Check defaults: run without any XDG_ variables set in the environment; expect the following results (my home directory is /home/liw and my UID is 1000):

    • config: /home/liw/.config
    • config dirs: /etc/xdg
    • data: /home/liw/.local/share
    • data dirs: /usr/local/share/:/usr/share/
    • cache: /home/liw/.cache
    • runtime: /run/user/1000
  • Set each environment variable to an empty value and check that the output has the default value.

  • Set each environment variable to a special value and check that the output has that value.

  • Set each variable to a value that is not an absolute, and check that the output has the default value.

Evaluation

cap-directories

This crate doesn’t seem to provide path names, only structs that represent the corresponding “open directory”. This may be a better abstraction for some use cases, but seems overkill for others, and constricting. How would a program tell the user at what path it expects a configuration file, for example?

platform-dirs

The documentation is not as clear as it could be, but I got things working, so I guess it’s good enough.

This crate has a “state directory”, but not a “runtime directory” and doesn’t seem to have that at all. In fact, the README says it’s been removed. This disqualifies it from my/our use, I think.

directories-next

This seems quite straightforward. Documentation is OK.

This crate insists that XDG_RUNTIME_DIR is set and does not have a default. I can live with that, even if it’s not great.

Conclusion

Of the three crates I looked at, directories-next is the clear winner.

Source code

The source code I wrote, what there is of it, is at https://gitlab.com/larswirzenius/xdg-experiments/.