Guide

Uploading builds to Steam

The complete SteamPipe workflow: download the SDK, write your build scripts, push the build with steamcmd, and set it live. Pick your operating system below. The script format is identical everywhere, only the commands differ.

Before you start

1
You need a Steamworks account with an App ID

Your game's App ID is shown in the Steamworks App Admin panel. Every app also gets at least one Depot ID, usually App ID + 1. Depots are the containers your game files are uploaded into. Find them under SteamPipe → Depots.

2
Download the Steamworks SDK

Get the latest SDK zip from partner.steamgames.com under Downloads. Extract it anywhere. Everything you need lives in sdk/tools/ContentBuilder/.

3
Understand the ContentBuilder folder
ContentBuilder/
├── builder/         steamcmd for Windows
├── builder_osx/     steamcmd for macOS
├── builder_linux/   steamcmd for Linux
├── content/         put your game files here
├── output/          build logs and cache (auto-generated)
└── scripts/         your .vdf build scripts go here

Copy your final game build into a subfolder of content/, for example content/windows/. Only ship what players need. Exclude debug symbols and editor leftovers (see engine notes at the bottom).

Write the build scripts

Two small text files in scripts/ describe what to upload. Replace 1000 and 1001 with your real App ID and Depot ID.

scripts/app_build_1000.vdf

"AppBuild"
{
    "AppID" "1000"
    "Desc" "v1.0.0 launch build"
    "ContentRoot" "..\content\"
    "BuildOutput" "..\output\"
    "Depots"
    {
        "1001" "depot_build_1001.vdf"
    }
}

scripts/depot_build_1001.vdf

"DepotBuild"
{
    "DepotID" "1001"
    "ContentRoot" "..\content\windows\"
    "FileMapping"
    {
        "LocalPath" "*"
        "DepotPath" "."
        "Recursive" "1"
    }
    "FileExclusion" "*.pdb"
}

The Desc text is what you'll see in the Steamworks build list, so make it meaningful, like a version number. FileExclusion lines can be repeated to skip more patterns. On macOS and Linux you can use forward slashes in paths.

Shipping for several operating systems? Create one depot per OS (e.g. 1001 Windows, 1002 macOS, 1003 Linux), one depot script each, and list them all in the app script. Assign each depot to its OS in Steamworks → Installation → General Installation.

Run the upload

1
Open a command prompt in ContentBuilder
cd C:\path\to\sdk\tools\ContentBuilder
2
Run steamcmd with your build script
builder\steamcmd.exe +login your_steam_account +run_app_build ..\scripts\app_build_1000.vdf +quit

steamcmd updates itself on first run, then asks for your password and a Steam Guard code. After the first successful login, credentials are cached and future uploads won't prompt.

3
Wait for "Successfully finished AppID 1000 build"

Upload speed depends on your connection and build size. Only changed files are uploaded on subsequent builds, so updates are much faster than the first push.

1
Open Terminal in ContentBuilder
cd /path/to/sdk/tools/ContentBuilder
2
Make the runner executable, then run it
chmod +x builder_osx/steamcmd.sh
./builder_osx/steamcmd.sh +login your_steam_account +run_app_build ../scripts/app_build_1000.vdf +quit

If macOS Gatekeeper blocks steamcmd, allow it under System Settings → Privacy & Security, or remove the quarantine flag:

xattr -dr com.apple.quarantine builder_osx
3
Enter your password and Steam Guard code

First run only. Look for "Successfully finished AppID 1000 build" at the end. Reminder for Mac builds: ship a proper .app bundle, and codesign + notarize it or players will face Gatekeeper warnings.

1
Install 32-bit libraries (steamcmd needs them)
# Debian / Ubuntu
sudo apt update && sudo apt install lib32gcc-s1

# Arch
sudo pacman -S lib32-gcc-libs
2
Run steamcmd from ContentBuilder
cd /path/to/sdk/tools/ContentBuilder
chmod +x builder_linux/steamcmd.sh
./builder_linux/steamcmd.sh +login your_steam_account +run_app_build ../scripts/app_build_1000.vdf +quit

Enter your password and Steam Guard code on first run.

3
Confirm the build finished

You want "Successfully finished AppID 1000 build". Linux tip: make sure your game binary has the executable bit set inside the depot, and set the correct executable path in your Steamworks launch options.

Set the build live

1
Open SteamPipe → Builds in Steamworks

Your new upload appears at the top of the build list with the Desc text from your script.

2
Assign it to a branch

Pick the build, choose a branch in the dropdown, then Preview Change → Set Build Live. The default branch is what players get. For testing, create a beta branch (optionally password-protected) under SteamPipe → Builds → Manage Branches and put the build there first.

3
Set launch options once

Under Installation → General Installation, add a launch option per OS pointing at your executable. Without this, Steam doesn't know what to run. Then publish the change via the Publish tab.

4
Test like a player

Install the game through the Steam client on a clean machine (or at least a clean folder), ideally via your beta branch. This catches missing redistributables like the VC++ runtime, the number one day-one bug.

Easier ways to upload

A
SteamPipeGUI (Windows, recommended for beginners)

Inside the SDK at sdk/tools/SteamPipeGUI.zip is an official Windows app that wraps everything above in a form. Unzip it, run it, fill in your App ID, Depot ID, content folder and Steamworks login, and click upload. It generates the .vdf scripts and runs steamcmd for you, and shows the log live. If the command line above made you nervous, start here; you can switch to scripts later for automation.

B
Browser upload (no tools at all)

Steamworks can ingest a build directly in the browser: go to your app → SteamPipe → Builds and use the upload option to submit a zip of your game folder. Steamworks unpacks it into your depot. This is the simplest path for small games and first uploads. Limits: it suits smaller build sizes, gives you less control over depot mappings and exclusions, and is slower for frequent updates since the whole zip uploads every time, whereas steamcmd only uploads changed files.

C
Which should you use?

First ever upload or tiny game: browser. Regular updates on Windows: SteamPipeGUI. Multi-OS depots, big builds or CI automation: the steamcmd scripts above. They all produce identical builds in the same build list.

Assigning builds: branches, depots, packages

Three concepts trip up every newcomer. Once they click, build management is easy.

1
Depots hold files, packages grant access

A depot is a container of files (one per OS is the usual split). A package is what a customer actually buys or activates, and it lists which depots they receive. Check App Admin → All Associated Packages and make sure every depot you upload is included in your store package, or buyers will download nothing. New depots are NOT added to packages automatically.

2
Branches decide which build players run

Under SteamPipe → Builds every upload appears in a list. A build does nothing until assigned to a branch. The default branch is what all players get. Create extra branches under Manage Branches: a password-protected beta branch is the standard pre-release testing setup. Players opt in via the game's Properties → Betas in their Steam client and enter the password.

3
Setting live, released vs unreleased

Select the build, pick the branch, Preview Change, then Set Build Live. Two situations: if your game is unreleased, putting a build on default is safe; nobody can download until you press the actual Release button on launch day, and that release flow confirms which build ships. If your game is released, setting a build live on default pushes the update to every player within minutes, so test on a beta branch first. Default-branch changes for released games ask for re-confirmation in Steamworks (and may require your login password) precisely because of that.

4
Rolling back

Shipped a broken update? Set the previous build live on default again; the build list keeps your history. This takes one minute and is the reason you never delete old builds.

Engine notes: what to exclude

EngineExclude from your depot
UnityThe *_BurstDebugInformation_DoNotShip folder, *.pdb files, and any *_BackUpThisFolder_ButDontShipItWithYourGame folder.
Unreal*.pdb debug symbols and the Saved/Intermediate folders. Package a Shipping build, not Development.
GodotExport release templates, not debug. Exclude .import caches if exporting manually.

Add these as extra "FileExclusion" lines in your depot script so they're stripped automatically on every upload.

Common errors

ErrorFix
Failed to commit buildUsually wrong App/Depot ID in the scripts, or your account lacks the "Edit App Metadata" and "Publish" permissions for this app.
Logged in elsewheresteamcmd logins can collide with a logged-in Steam client on the same account. Use a dedicated builder account with limited permissions.
Rate Limit ExceededToo many failed login attempts. Wait 30 minutes, double-check the password.
content root not foundThe relative paths in the .vdf resolve from the scripts folder. Check ContentRoot points at a folder that exists.
Depot ... is not includedThe depot isn't attached to a package. Check the depot is listed in your app's package under App Admin → All Associated Packages.
Automating this later: the same steamcmd command works in CI (GitHub Actions, GitLab CI) using a builder account. Valve's official docs live under partner.steamgames.com → Documentation → SteamPipe.