Push builds
Publish a build of your game with depot push, with launch targets, release notes, DLC packages and resumable uploads.
depot push takes a folder with your game build, turns it into a signed, encrypted release and uploads it to Depot. Run it once per platform for each version you ship.
depot push --game my-game --platform windows-x64 --release 1.2.0 \
--input build/windows/ --launch-file launch-windows.json \
--channel stable --note "New boss, faster loading, two crash fixes."Before your first push you need a game (depot game create) and an enrolled signing key (depot keys generate and depot keys enroll). The Quickstart walks through both. Signing keys are covered in Signing keys.
What you pass
Prop
Type
The full list, including chunking and upload tuning, is in the CLI reference.
The input folder
Point --input at the folder you would zip up for players. Every regular file under it becomes part of the release, with its relative path and its executable bit. Symlinks, hardlinks and special files are refused, so resolve them in your build step.
Anything you leave in the folder ships. Remove debug symbols, logs and local config first if players shouldn't get them.
Platforms
A release is for one platform. Platform names are lowercase letters, digits and -, up to 32 characters. The CLI names machines like this:
| Platform | Name |
|---|---|
| Windows, x64 | windows-x64 |
| macOS, Apple silicon | macos-arm64 |
| macOS, Intel | macos-x64 |
| Linux, x64 | linux-x64 |
Without --platform, the CLI uses the platform of the machine it runs on. Set it explicitly when you push a Windows build from a Mac or from CI.
Release names are per platform, so you push 1.2.0 once for windows-x64 and once for macos-arm64. Each platform has its own channels too. See Channels and releases.
Release names are permanent
Once a release is published, its name can't be reused on that platform. Pushing a name that's already published fails with a 409 conflict. Pick a new name, such as 1.2.1.
Launch targets
A launch file tells the launcher which file to start, with which arguments and from which folder. It's a JSON array of launch targets, one per platform. Every target is checked against the build you push, so give each platform's build its own launch file.
[
{
"platform": "windows-x64",
"path": "MyGame.exe",
"args": ["--skip-intro"],
"working_dir": "."
}
]Prop
Type
depot push checks the launch file against the build before it uploads anything:
- Each target's
pathmust be a file in this build (or a.appbundle folder on macOS). - There's at most one target per platform.
- On macOS and Linux, the file must have its executable bit set.
envcan't set variables that change how programs load or which shell runs, such asPATH,HOME,LD_*,DYLD_*,TMPorSHELL.
If a check fails, nothing is uploaded. Fix the file and push again.
Release notes
--note is the text players see under What's new on your store page. It's attached to the channel move, so it needs --channel:
depot push --game my-game --platform linux-x64 --release 1.2.1 \
--input build/linux/ --channel stable \
--note "Fixes the save bug on the second island."Notes are plain text. Depot keeps the first 500 characters. You can also add a note when you move a channel later with depot channel set --note.
Encryption
Every game on Depot is restricted. Each push encrypts the build chunk by chunk with AES-256-GCM, and only players who own the game can get the key to decrypt it.
The content key is made on your machine. The first push to a package generates it, registers it with Depot and writes a backup file:
~/.config/depot/content-keys/<domain>.jsonDepot stores its copy wrapped under its own key. It releases the key only to a download session for your game, which players get from an active entitlement, and it never returns the key to you.
Back up the content key file. Every later push to the same package needs it, from any machine. If you push from CI, store it as a secret and pass it with --content-key. See CI and agents.
You don't need --encrypt. It only matters for older public games, and every new game is encrypted anyway.
Only changed bytes are uploaded
Depot splits files into content-defined chunks. A chunk's id is the hash of its bytes, so an unchanged part of a file has the same chunks in every release, even when bytes were inserted before it.
When you push, the CLI fetches the list of chunks already published for the package and only compresses, encrypts and uploads chunks that are new. The report at the end shows the release's sequence number and id, how many chunks were reused and how many were new, how much was uploaded, and the channel's new revision if you passed --channel. Add --json to get the same report as an object.
Players benefit the same way. An update downloads only the chunks their installed copy doesn't have, and reuses the rest from disk after checking them.
Chunks are reused within one package. A DLC package has its own content key, so it never shares chunks with the base game.
Interrupted pushes resume
A push builds into a staging folder in the CLI's state directory (~/.local/state/depot/push/ by default), then uploads. If the upload stops because of a network error, a closed laptop or a cancelled CI job, run the same command again:
- If the input folder and launch file haven't changed, the CLI reuses the staged build instead of building again.
- The release reservation is reused, so the release keeps its sequence number.
- Objects Depot already has are skipped. Large packs are uploaded in parts, and parts already uploaded are skipped too.
Pass --rebuild to throw away the staged build and start the build again.
Uploads go straight to storage
The CLI never sends your build through the API. Depot gives it short-lived presigned URLs, and it uploads each object directly to storage. Objects over 64 MiB use multipart uploads. See Uploads never pass through the API.
What Depot checks before it publishes
A release becomes visible only after Depot has checked it:
- Every object the release needs exists in storage at its exact size.
- The signed descriptor matches the reserved release: game, platform, name, sequence and package.
- The descriptor names the package's content key by its check value.
- The signature verifies with an active signing key enrolled for the game.
- The manifest and index match their SHA-256 hashes, and the index lists exactly the packs the descriptor lists.
The release then has the status published and can go on a channel. A release that fails a check is never shown to players.
The launcher checks again on every install and update. It verifies the signature with the keys it trusted when the player first installed, refuses releases older than what's installed, checks every chunk's hash after decryption, and checks every file before it switches to the new version. A broken or tampered release can't be installed, and a failed update leaves the old version in place.
DLC and other packages
A package is something players can own: the base game, a DLC, a bundle or a test build. Releases go to the base package unless you say otherwise.
To publish content for another package, create it once and push with --package:
depot package create --game my-game --name expansion-1 --kind dlc --title "The Frozen Coast"
depot push --game my-game --platform windows-x64 --release 1.0.0 \
--input build/expansion-1/ --package expansion-1The first push to the new package generates its own content key and backup file.
The launcher and depot install install the base package. You can also ship DLC content inside the base build and unlock it in the game with an ownership check from the Depot SDK. How players get packages is covered in Keys and access.
After a push
depot release list --game my-game --platform windows-x64
depot channel show --game my-game --platform windows-x64 --channel stableIf you pushed without --channel, the release is published but players don't get it until you move a channel to it. See Channels and releases.