The tmpfiles.d mechanism in systemd is how you tell the system to manage temporary files and directories for you, ensuring they’re cleaned up or set up correctly at boot or at specific intervals.

Let’s see it in action. Imagine you have a service that creates a temporary directory for its logs, but you want to make sure it’s cleaned up after 3 days, and also that it’s created with specific permissions.

Here’s a tmpfiles.d configuration file, let’s say /etc/tmpfiles.d/my-app.conf:

# Type Path        Mode  Age   User  Group ID
d     /var/run/my-app 0755  3d    root  root

When systemd boots, it reads this line.

  • d means it’s a directory.
  • /var/run/my-app is the path it will manage.
  • 0755 are the permissions: owner can read/write/execute, group and others can read/execute.
  • 3d means it will be removed if it’s older than 3 days.
  • root root specifies the owner and group.

If you run systemd-tmpfiles --create, you’ll see it in action:

# Initially, the directory doesn't exist
ls -ld /var/run/my-app
# ls: cannot access '/var/run/my-app': No such file or directory

# Now, let systemd create it
sudo systemd-tmpfiles --create

# Check if it exists and has the correct permissions
ls -ld /var/run/my-app
# drwxr-xr-x 2 root root 4096 Oct 26 10:00 /var/run/my-app

# If you want to simulate aging, you can manually touch it and change times
sudo touch -d "4 days ago" /var/run/my-app
sudo systemd-tmpfiles --clean

# And it would be gone (or rather, its contents if it had any and was a file)
# For directories, it cleans empty directories that are too old.
# If you had a file inside:
# f /var/run/my-app/temp.log 0644 3d
# sudo systemd-tmpfiles --clean would remove temp.log

The core problem tmpfiles.d solves is the ad-hoc, often forgotten, cleanup scripts that used to litter /etc/cron.daily/ or /etc/rc.local. These were brittle, hard to track, and often duplicated logic. tmpfiles.d centralizes this management, making it declarative and integrated with systemd’s lifecycle.

There are several types of entries you can define:

  • f: a regular file.
  • d: a directory.
  • c: a character device.
  • b: a block device.
  • p: a named pipe (FIFO).
  • s: a socket.
  • v: a whiteout entry (used in overlay filesystems, less common for typical use).

The Age field is powerful. It can be specified in days (d), hours (h), minutes (m), or seconds (s). You can also use ! to force immediate cleanup of existing files that match the pattern, regardless of age, for example f /tmp/my-cache !.

Systemd’s tmpfiles.d service runs at specific times:

  • During early boot (systemd-tmpfiles-setup.service).
  • At boot for cleanup (systemd-tmpfiles-clean.service).
  • Periodically (e.g., daily via a systemd timer, systemd-tmpfiles-clean.timer).

The systemd-tmpfiles --verify command is your best friend for checking syntax errors in your .conf files without actually performing any actions.

The Path can also include wildcards. For example, d /var/log/myapp-logs/ 0755 - root root would manage all subdirectories within /var/log/myapp-logs/. The - for age means "don’t clean based on age," but it will still be created if it doesn’t exist and cleaned if it’s empty and the system is shutting down if configured to do so.

One subtle but crucial detail is the interaction between tmpfiles.d and other systemd units. If a service unit (like a .service file) creates a file or directory, and tmpfiles.d is configured to manage that same path, the tmpfiles.d configuration will take precedence for cleanup. This means you should be careful not to have conflicting management strategies. For instance, if your service creates a directory and expects it to persist for the lifetime of the service, but you also have a tmpfiles.d rule to clean it after 1 day, the directory might disappear unexpectedly. It’s often best to let tmpfiles.d manage truly temporary or cache-like data, and rely on service logic for state that the service itself needs to maintain.

You can also specify a "maximum" size for files/directories. For example, d /var/cache/myapp 0755 7d - - 1G would ensure that the directory and its contents don’t exceed 1 gigabyte, cleaning up the oldest files if it does. This is less commonly used than the age-based cleanup but very useful for managing disk space.

The next step in managing system resources declaratively is understanding how systemd timers can be used to schedule arbitrary commands, not just cleanup.

Want structured learning?

Take the full Systemd course →