Tux sitting in a Flatpak box with Steam logo

Flatpak, Steam Cloud, and XDG Base Directories — why your Linux game progress isn’t being synced

If you’ve installed Steam on Linux through Flathub, chances are that Steam Auto-Cloud — Steam’s free game progress synchronization service — won’t work for many of your games that are built with the markets most popular game engines. I have dug into why it isn’t working, and discuss two possible solutions to fix the problem.

Before we get into the issue, I’ll first need to establish quite a bit of context regarding where games and applications store their configuration files and user data, and how they decide on where to store it. If you’re already familiar with the XDG Base Directory specification, you can glance at the tables and skip straight to the third section.

Where applications should store their configuration and data

Historically, applications on Linux would store their configuration and other files in a hidden directory inside each user’s home directory. This created a huge mess in the home directory, and the legacy from those ancient times still drive neat-freak users insane to this day.

The XDG Base Directory specification provides a set of rules for where configuration and user data, cache data, and other common data types should be stored in order to clean up people’s home directories. A tidier home directory provides other benefits such as easier to configure backups.

The XDG Base Directory specification specifies two folders of particular interest: the $XDG_CONFIG_HOME directory for user-specific application configuration data (defaults to ~/.config/), and the $XDG_DATA_HOME directory for user-created data files (defaults to ~/.local/share/). XDG Base Directory compliant applications should first attempt to read these values from the environment variables, or fallback to the default paths if these variables aren’t set in the runtime environment.

Other operating systems have similar directory schemes such as the Application Support and Configurations directories in the user Library directory on macOS; and the Local, LocalLow, and Roaming directories in the user AppData directory on Windows.

Flatpak overrides the XDG Base Directory defaults

Flatpak can run applications in a limited environment where applications can’t read and write to the user’s home directory (~/). Each application instead get their own data directory at ~/.var/app/com.example.Application/ for storing persistent user data. The Flatpak runtime environment overrides the XDG base directories per-application by pointing the override environmental variable to the application specific directories in the per-application Flatpak data directory.

The below table shows where XDG base directories are located by default, and where they are located inside the per-application Flatpak data directory:

Env. variable XDG default path Flatpak path
$XDG_CACHE_HOME ~/.cache/ ~/.var/app/com.example.Application/cache/
$XDG_CONFIG_HOME ~/.config/ ~/.var/app/com.example.Application/config/
$XDG_DATA_HOME ~/.local/share/ ~/.var/app/com.example.Application/data/

Applications that don’t comply with the XDG Base Directory standard and don’t read the environmental variables will end up storing data in the wrong directory outside the per-application Flatpak data directory. Note that depending on the specific Flatpak application, the home directory may not be readable or writable. A more secure Flatpak application will be more limited, but Steam has broader permissions than many other applications as Steam itself is meant to be used as a runtime for other third-party applications downloaded through the service.

Games built using either of the two popular game engines Unity 3D or Unreal Engine will by default save game progress to $XDG_CONFIG_HOME/unity3d/GameStudioName/GameName/ or $XDG_CONFIG_HOME/Epic/. These games will correctly pickup on the overriden XDG environmental variable and save their game progress inside the Flatpak per-application data directory created for Steam. This is provided for game developers by the data storage functions in the game engines, and these game engines use the XDG Base Directory specification. Game developers may not be too familiar with the Linux platform and may be completely unaware that Unity 3D and Unreal Engine may store data at any paths other than the default.

Games built on other game engines, or games that don’t use the directory-mapping functions provided by their game engines may hardcode the default directories or save to other directories entirely.

Steam Auto-Cloud

Game developers can provide game-progress synchronization as a free add-on service to their customers through one of two integration options: the Steam Cloud API or Steam Auto-Cloud. Most developers prefer the latter because it doesn’t require any changes to the game’s code. Instead, developers configure Steam to automatically synchronize a directory or set of files at an arbitrary location in the home folder.

To configure Auto-Cloud, developers must first select one of 14 predefined directory root directory variables which map to specific directories on the file system; and then setup the path and file patterns they want to synchronize. Auto-Cloud actually works like most other consumer-grade file synchronization services, and Steam will automatically synchronization the files specified by game developers at the beginning and end of your gaming sessions.

For the Linux platform, there are two documented and one undocumented Steam Cloud root directory variables available:

Steam Cloud root Env. variable Default path Comment
LinuxHome $HOME ~/
$XDG_CACHE_HOME ~/.cache/
LinuxXdgConfigHome $XDG_CONFIG_HOME ~/.config/ Undocumented.
LinuxXdgDataHome $XDG_DATA_HOME ~/.local/share/

According to Steam Database, there are only six games in the entire Steam game catalog that have configured Steam Cloud to use the undocumented LinuxXdgConfigHome root. 114 other games have instead set their root to LinuxHome and hardcoded the path .config. This means that only six of the games that store data in the $XDG_CONFIG_HOME directory will synchronize game progress to and from the correct $XDG_CONFIG_HOME path inside Steam’s data directory in Flatpak. The 114 other games that use the hardcoded path will instead save to the user’s home directory instead.

Auto-Cloud path mapping example for a Unity 3D game

Auto-Cloud configuration example for a Unity 3D game using the wrong root. Image courtesy of Steamworks documentation, Valve Corporation. Larger image.

As previously mentioned, the LinuxXdgConfigHome variable isn’t part of the Steam Auto-Cloud documentation that Valve offers to developers. Instead, Valve suggests that developers choose the LinuxHome variable and hardcode the .config directory path. Thanks Valve….

An estimated 450 other games also use LinuxHome and either hardcodes the path to .local/share/ or use different paths entirely.

So what can be done about fixing Steam in Flatpak?

This is a difficult problem to get right. The earliest version of Steam that was published on Flathub in got this partially right. It created a new home directory inside the $XDG_DATA_HOME directory inside the data directory at ~/.var/app/com.valvesoftware.Steam/home/. It would then rewrite the $HOME variable to this path and would thus ensure everything would be stored inside Steam’s data data directory.

However, this solution didn’t go far enough in overriding environmental variables. Steam Auto-Cloud and games that had hardcoded their directory paths relative to the home directory worked splendid with this setup. The XDG Base Directory environmental variables, which are overridden in Flatpak runtime environments, still didn’t pointat the same directories even when the home directory was moved inside the Flatpak data directory. The following table shows paths and variables relative to the root of the data directory at ~/.var/app/com.valvesoftware.Steam/.

Steam Cloud root Env. variable Flatpak path Proposed override
LinuxHome $HOME ./home/
$XDG_CACHE_HOME ./cache/ ./home/.cache/
LinuxXdgConfigHome $XDG_CONFIG_HOME ./config/ ./home/.config/
LinuxXdgDataHome $XDG_DATA_HOME ./data/ ./home/.local/share/

This approach was reverted at the end of , and Steam was granted permission to write to the actual home directory instead. This lowers the level of security that the Steam Flatpak can provide. However, the XDG Base Directory overrides remained untouched.

I can suggest two possible solutions:

1. Move $HOME back into the Flatpak data directory and override XDG variables

The first solution is to restore the original idea of moving the home directory into the Flatpak data directory and overriding the $HOME variable (re-homing). The same launcher script that sets up this override could then also override the thee XDG base directory environmental variables discussed in this article to point to their default paths inside the re-homed home directory. Every application should then agree on where data is stored.

The launcher would also have to create these three directories inside the re-homed home directory as Steam assumes that these directories exist already on it’s first launch and will crash if they don’t exist.

2. Override the XDG overrides to restore their defaults

The second solution is to abandon re-homing and the idea of neatly keeping application user-data away from the actual home directory. Instead, the launcher script could be modified to override the Flatpak overrides of the three XDG Base Directory variables discussed in this article to point each of them to their default paths in the actual home directory. Much like the first suggested solution, this should make every application agree on where data is stored.

You may notice that these proposed solution acknowledge that it’s near impossible to actually change the XDG Base Directory variables and focus on mapping them to their default values. There are simply too many applications that have made assumptions about the environment without being familiar with the Linux desktop ecosystem. Given that all the applications we’re dealing with are closed-source, there isn’t much the community can do to fix the situation.

Both of the above solutions will cause some players to lose their local game progress. The task of migrating possibly hundreds of unknown directories from multiple unknown paths and merging them to another unknown path is simply too complex to automate. Even given perfect knowledge of all the directories involved wouldn’t help much as automating conflict-resolution of both local duplicates and conflicting Steam Cloud saves would surely cause data loss for players.

The status quo

So the current situation is a bit of a mess.

Players shouldn’t install Steam through Flathub until these issues are resolved. There will be a data loss at some point down the line when the issues discussed in this article are resolved.

Players can temporarily work-around the issues by creating elaborate symlinks between the mismatched directories mentioned in this article. However, in my testing I found that many games don’t follow symlinks and some actually crash on start-up if their data directories are symlinked.

The only thing I fault Valve Corporation with in all of this is to recommend hardcoding the .config directory inside their LinuxHome root variable instead of recommending developers use their LinuxXdgConfigHome root variable. I’ve contacted Valve regarding updating their documentation.


Thanks to Pavel Djundik of Steam Database for digging up numbers on the roots and paths used by Linux games in their Steam Auto-Cloud configuration!

Sources