Steam Auto-Cloud cross-platform save game synchronization

24. January 2026

I recently added cross platform save game synchronization to my game. It is designed to work with the Steam Auto-Cloud, without using the SteamSDK. Therefore no SteamSDK specific code is needed in the game. This make the game compatible also with other file synchronization software, such as Syncthing.

My game is Open Source and APLv3 licensed and that makes it incompatible with the SteamSDK anyways. This way I can release a copyleft game on Steam with the minimum Cloud Sync support. It is made with the Godot Engine 4.x, but I will not show any code here. A save game implementation is in most cases too specific for a game. It simply makes more sense to just show the overall idea behind it.

What should be synced

First of course, all save game files that contain game progress need to be synchronized. This are the most important files and they should be handled with care. Nobody wants to loose progress and restart from the beginning.

Some other files instead, should always be excluded, like

It also makes sense to divide user settings into local only and synchronized. Settings that should be synced are

Settings that should not be synced are

For some settings it can get difficult to decide if they are local or synced. A good example for this is the UI theme. A user might prefer dark themes on the SteamDeck OLED screen, to save battery. But uses light themes on all other devices. In this special cases, it could make sense to let the user decide, if a specific setting is synced. This could be a simple checkbox that enables/disables the sync between devices.

In summary all save game files, but only some settings, should be synchronized. This is the basic and simplified structure of the user directory of my game (on Linux).

.local/share/99managers-futsal-edition
    local/
        settings_local.csv
        version.txt
    sync/
        deleted_save_games.csv
        settings_sync.csv
        save_games/
            136907-518000-261045/
                checksums.csv
                cups.csv
                inbox.csv
                leagues.csv
                ...

Everything in the sync directory gets synchronized. This makes it easy to setup synchronization, because the whole directory is affected. It contains the sync settings and all save game files. The deleted save games file is the only special file Steam needs and I will explain its use later.

Off topic: you might ask yourself why the hell I use csv files? Well, I tried a lot of formats like ini files, Godot Resources and json files. But the ability to let also non-developers inspect them with tools they know convinced me.

Atomic saving and backups

Crashes or other unexpected terminations of the game while saving can lead to corrupted files. The more time it takes to save the state to disk, the higher the probability that this will happen. For that reason it makes sense to implement atomic saves.

Instead of overwriting directly the current save files, they are written to new staging files. So if the save process is interrupted, the real save files stay untouched. Once all files are written to disk, you overwrite the real save files with the staging ones.

To be even more safe and fail proof, you can add backups to the atomic save cycle. This can be achieved by simply renaming the active save to something else, before overwriting it.

In my case I even save two backups of every file I save to disk. So the atomic save process with double backups is the following

  1. write all files to staging/
  2. rename backup1/ to backup2/
  3. rename active/ to backup1/
  4. rename staging/ to active/

Note: The second step can be skipped, if a single backup is enough. If something goes wrong in a step, there are still backups from where the user can recover.

With this approach my user directory looks like this

.local/share/99managers-futsal-edition
    local/
        settings_local.csv
        settings_local.csv.backup1
        settings_local.csv.backup2
        version.txt
    sync/
        deleted_save_games.csv
        deleted_save_games.csv.backup1
        deleted_save_games.csv.backup2
        settings_sync.csv
        settings_sync.csv.backup1
        settings_sync.csv.backup2
        save_games/
            136907-518000-261045/
                active/
                    checksums.csv
                    cups.csv
                    ...
                backup1/
                    checksums.csv
                    cups.csv
                    ...
                backup2/
                    checksums.csv
                    cups.csv
                    ...

This of course increases the total disk usage of the user directory. But it makes a really robust and fail proof save process.

Corruption detection

Now I still need to figure out if a file has been corrupted. For that I use a checksums file, that contains the sha256 sum of every file, after it was saved. Every save state has it's own checksums file. Before loading a file, I check that it still has the correct sha256 sum. If a save game file is corrupted, I let the user decide, if a backup should be loaded. I let the user also skip the checksum validation, in case files where modified intentionally.

It is important to know that Steam Auto-Cloud does not synchronize empty files. For that reason I also save empty files to that list, with the sha256 sum of an empty string:

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

If a file from the checksum list is not found, I can check if it should be empty. A simple boolean flag, that is true if the file is empty, would actually also do the job.

Steam Auto-Cloud

Now that you know what needs to be synced and how to securely safe files, you can synchronize them.
To use the Steam Auto-Cloud feature, it needs to be enabled for your game. How this is done might change in future, so it does not make any sense to write it down here. Just follow the official documentation, that (hopefully) will always be updated and have the correct information.

Cross platform configuration

Once it is enabled, you can decide what directories get synced between devices. To do that, you need to set a root path with root overrides for the other operating systems. Because Windows still has the biggest market share on Steam, it makes sense to make Windows root.

Set the following configuration at Steamworks > App Data Admin > Application > Steam Cloud.

Root paths (Windows)

Root WinAppDataRoaming
Subdirectory 99managers-futsal-edition\sync\
Pattern *
OS All OSes
Recursive Yes
Cross platform Yes

Root overrides (Linux)

Original root WinAppDataRoaming
OS Linux + SteamOS
New root LinuxXdgDataHome
Add/Replace path 99managers-futsal-edition/sync/
Replace path Yes

Root overrides (MacOS)

Original root WinAppDataRoaming
OS MacOS
New root MacHome
Add/Replace path /Library/Application Support/99managers-futsal-edition/sync/
Replace path Yes

To make this platform specific instead, simply use a dedicated root path for every OS. The files would be synced only between devices with the same OS.

Note: This setup is specific for my game made with Godot Engine 4. Other engines might use different directories to save user files. Anyway the way to organize the root directories should remain the same.

Deleting save games

Steam does not delete files or directories on other devices. This means if you delete a save game on a device, it will still exist on the other devices. My game scans the save directory for files, so a deleted state would show up again on another device. For that the deleted save games file is needed, to make sure that they get deleted everywhere.

My deleted save games file contains the ids of deleted save states. If a save state with a deleted id is scanned, it gets moved to the trash. Alongside every deleted id, I also save the time stamp of the deletion. That allows to periodically remove all ids that are older than one year.
Note: This is only needed for Steam Auto-Cloud. Syncthing for example can delete files between devices, if configured to do so.

I never permanently delete files, but move them to the operating systems trash. This assures that in most cases everything can be recovered from there. If you want to have 100% file recovery, a custom trash directory can help. Deleted files get moved to the custom trash and then the user empties that trash manually. This would also work where no trash system exists, such as web or iOS.

Sync conflicts

The Steam client will inform the user, when a conflict happens. The user can choose what save state to keep, by looking at the last modified time stamp. This means no special logic is needed inside the game.

The Steam client triggers the sync before a game is opened and after it is closed. Most conflicts happen if the sync failed, because of missing network connection. Or if a game is played simultaneously on different devices, but that is less common.

Steam Auto-Cloud vs Cloud API

The Steam Cloud API has more features, than the simple Auto-Cloud. It brings fine-grained sync support, where you can choose which file gets synced when. The Auto-Cloud simply synchronizes the states when the game is opened and when it's closed. The API instead can upload and download files, while the game is running. This adds interesting features for the Steam Deck, like Dynamic Cloud Sync. This allows to suspend a game, continue on another device and then resume again on the Steam Deck. Of course, without losing any progress by synchronizing all files that changed in the meantime.

Implementing such features require the SteamSDK and lot of sync logic in the game. But I guess it depends on the type of the game what type of Cloud sync makes sens.

Great, now the code please

If you want to see how I implemented this in my game, check out the repository on Codeberg. Just poke around the game/src/ directory and you should find the code where all this happens.

To see the code in action, get the game on 99managers.org!

Every feedback is welcome

Feel free to write me an email at info@simondalvai.org and comment on Mastodon.

mastodon button Codeberg button Email button RSS button