Guide · Publishing

How to publish an Unreal Engine game to Steam

Packaging a build is the part everyone expects to be hard. Getting it into Steam is the part that actually eats the weekend: depots, SteamPipe, a builder account, a two-factor prompt on a machine you are not sitting at. Here is the whole path, once, so it is boring every time after.

14 min read

What you need before you start

Five things. Four of them are one-time, and the fifth is the commit you were going to make anyway.

  1. A Steamworks app.You need an App ID and at least one depot ID. Depot IDs are conventionally your App ID plus one, and Steamworks shows both under SteamPipe in your app's admin pages.
  2. A Steam builder account. Use a dedicated account with only the Edit App Metadata and Publish permissions, not your personal Steam login. If that account is ever compromised, the blast radius is one app instead of your whole library.
  3. steamcmd. It ships inside the Steamworks SDK at tools/ContentBuilder/builder/. Valve's license is yours, not ours, so nobody redistributes it for you.
  4. The engine your project targets. Whatever version your .uproject asks for, installed on this machine.
  5. Your project, committed. A build you cannot trace back to a commit is a build you cannot reproduce.
Make the builder account a separate account. Valve recommends it, and it is the single cheapest security decision in this entire guide.

Step 1: get your project ready to package

Packaging writes a lot of files, and none of them belong in source control. If your project already has the standard exclusions, you are done; if not, confirm these are ignored:

Saved/            # transient editor + cook output
Intermediate/     # build intermediates
DerivedDataCache/ # cached derived data
Binaries/         # compiled DLLs
Build/            # packaging output

This matters more than it looks. A 90-minute cook writing tens of thousands of files into a folder that source control is watching will fight you the entire time. USourceControl checks these exclusions before a build starts and warns loudly if any are missing.

Then set the version you are shipping. Type it once, in the Releases panel, and it goes into three places at the same time: the project's ProjectVersion in Config/DefaultGame.ini, the label on the build, and the build description Steam shows in your build list.

One version string in three places is the whole point. The alternative is a bug report screenshot showing a version number that does not match anything you can find, and an afternoon spent working out which build the player actually had.

Commit. If you want the rule rather than the habit, turn on require a clean tree and a build will refuse to start while anything is uncommitted.

Step 2: package the build

Open Releases in the desktop app, pick your platform and configuration, and press Build. For a Steam release that is almost always Win64 and Shipping.

Configurations, briefly, because picking the wrong one is a classic first mistake:

  • Development keeps the console, logging, and debug features. Right for internal playtests, wrong for players.
  • Test is Shipping plus a few profiling and console hooks. Useful for QA and performance passes.
  • Shipping strips debug functionality and is what you send to customers.

Preflight runs before the cook does. It checks free disk space, whether Windows long paths are enabled, whether the archive directory is writable, whether the engine your project asks for is installed, and whether packaging output is excluded from source control. Every one of those is a failure that would otherwise surface forty minutes into a build, which is exactly when you have stopped watching.

Then it runs. You will see phases rather than a bar that lies: compiling, cooking, staging, packaging, archiving, verifying. A first Shipping cook on a real project can genuinely take hours, so set a build time limit you are comfortable with. Anything that runs past it is stopped and marked failed rather than holding the machine all night.

The finished build is archived outside your project folder. That is deliberate: a packaged build inside your working tree is how gigabytes of cooked output end up in a commit.

Step 3: connect your Steamworks app

In the Releases toolchain settings, browse to your steamcmd.exe. Then press Prepare once.

That step exists for a real reason: steamcmd updates and restarts itself the first time it runs, and its output during that is unparseable. Doing it deliberately now means it does not happen in the middle of your first upload, where it looks exactly like a hang.

Now fill in the Steam target for your project:

  • App ID and depot ID from Steamworks.
  • Builder account username. A username is not a secret, so it is stored in the clear.
  • Password, optionally. steamcmd caches a login token after your first successful sign-in, so a machine that has published before does not need one at all. Store it only if you want unattended uploads to survive that token expiring. It is encrypted by your operating system's keychain and handed to steamcmd over standard input, never on a command line where another process could read it.
  • Build description, which is internal metadata Steamworks shows in your build list. Templates like {version} {platform} {configuration} keep it honest without typing.
  • File exclusions, if you want to keep things like *.pdb out of the depot.
Credentials never leave your machine. They are encrypted locally, never sent to USourceControl, and cannot be read back out of the interface that set them. If your operating system cannot encrypt them, the app refuses to store them at all rather than storing them weakly.

Step 4: do a dry run first

Before your first real upload, publish with dry run enabled. It walks the whole path, signs in, resolves your depot, validates the content root, and transfers nothing.

A dry run costs a minute. A failed real upload costs you a half-finished build in your app's history and a conversation with yourself about which build ID is the good one. Do the dry run.

Step 5: upload to Steam

Press Publish, pick Steam, and it goes. The first sign-in on a new machine will ask for a Steam Guard code, which the app prompts for in-window rather than leaving steamcmd waiting on a hidden input nobody can see.

During the upload you get phases rather than silence: authenticating, scanning, uploading, committing, finalizing. Steam does not report a percentage, so the honest signal is how long it has been since steamcmd said anything at all, and that is shown directly. A tool that has been quiet for six minutes is usually working. Now you can tell the difference.

On success you get the Steam build ID, parsed straight out of SteamPipe's output, a link to your Steamworks builds page, and a permanent entry in your publish history with the build label, duration, and log.

Occasionally steamcmd exits with a nonzero code but has already printed a build ID, meaning the build probably did land. That is reported as ambiguous rather than retried, because retrying would create a duplicate Steam build. Check Steamworks, then decide.

Step 6: set the build live (and what Steam won't let a tool do)

Your build is in Steamworks. It is not in front of players yet, and this is the part most tooling glosses over.

You can set a build live on a beta branch from the command line, and USourceControl will do it as part of the upload if you name one. That is how you get a build to your QA testers or your closed beta without touching the web interface.

You cannot set the default branch live from the command line. Valve does not allow it. Promoting a build to your public default branch is a deliberate action in Steamworks App Admin, by a human, on purpose.

This is a good constraint. The gap between "the build uploaded" and "players have it" is the last place a bad build can be caught, and it costs you one click.

So the honest wording is that USourceControl uploads builds. Whether players get them stays yours.

Step 7: stop pressing the button

Once a project has shipped a handful of times, the Publish click is no longer a decision. Turn on auto-publish for the project and any build that succeeds uploads itself to the stores you selected, in order, one at a time.

It stays deliberately cautious. A store that is only half configured is skipped with a sentence naming what is missing, rather than failing the whole chain and leaving the stores that were ready without your build. And it still stops at uploaded, because Steam and Epic both keep the promotion step for a human.

If you want builds to happen without you being at the machine at all, that is a different tool: USourceControl Forge runs on a spare machine, builds on commit, and publishes releases for your team.

The Epic Games Store and itch.io, briefly

The same build goes to the other two stores from the same panel.

Epic Games Storeuploads through BuildPatchTool, which the app can download for you, around 90 MB. You supply your organization, product, and artifact IDs plus a BuildPatchTool client ID and secret, and the path to your game's executable relative to the build root.

The single most common Epic setup mistake is using your EOS SDK client ID, the ones that usually start "xyza", instead of your BuildPatchTool credential. They are different credentials. The app shows a masked preview specifically so you can catch it before an upload fails.

Epic's build version must be unique per artifact across platforms, so the same string cannot be both your Windows and your Mac build. The default template encodes the platform for you. And like Steam, self-service organizations make a build live from the Epic Developer Portal, not from the tool.

itch.io is the simplest of the three and the one most indies actually ship to. Butler takes a directory and pushes it to user/game:channel. You need the target, a channel name that tells itch which download to show which operating system, and an API key from your itch.io settings. Butler also reports real progress, so you get an actual percentage and transfer rate rather than an educated guess.

itch.io is the one store where a push goes live immediately. That is how itch works. If you want a staging step, push to a separate channel first.

When it goes wrong

The failures you are most likely to hit, and what they mean.

  • The build fails minutes in. Usually the engine, the compiler toolchain, or disk space. Preflight catches most of these before the cook starts, so read what it flagged rather than the tail of a 200 MB log.
  • Cooking fails on a specific asset. This is your project, not the pipeline. The log names the asset. Open it in the editor and cook that one asset to reproduce quickly.
  • steamcmd sits silent for minutes. Usually normal, especially while it walks a large depot. The quiet timer tells you how long it has actually been, so you can wait with confidence instead of killing a working upload.
  • Login fails on an unattended run. The cached login token expired. Store a password, or sign in once interactively to refresh the token.
  • Long path errors on Windows. Enable long paths. Unreal plus a deep content hierarchy plus a staging directory passes 260 characters faster than you would think. Preflight checks this.
  • The upload succeeded but nothing changed for players. Expected. Uploading is not promoting. Go and set the build live in Steamworks or the Epic Developer Portal.

Every build and every upload keeps its own log, readable inside the app, with credentials already redacted. Publish history keeps the build label, duration, bytes moved, exit code, and store link, so "what did we actually ship in March" stays answerable.

Frequently asked

Do I need a Steam Partner account to follow this guide?

Yes. Steam publishing requires a Steamworks account with an app you have already set up, which involves Valve's application fee and their review process. This guide covers everything after that point: packaging your Unreal build and getting it into your app's depot.

Can USourceControl set my game live on Steam automatically?

On a beta branch, yes. On the default branch, no, and not because we chose not to. Valve does not permit setting the default branch live from the command line, so promoting a build to the public branch stays an action in Steamworks App Admin.

Where are my Steam credentials stored?

Encrypted by your operating system's keychain, on your machine only. They are never sent to USourceControl, never placed on a command line where another process on the same Windows session could read them, and never readable back out of the app's interface. Your password goes to steamcmd over standard input.

Do I have to store my Steam password at all?

Usually not. steamcmd caches a login token after your first successful interactive sign-in, so a machine that has published before does not need one. Store a password only if you want unattended auto-publish to keep working after that cached token expires.

How long does a Shipping build take?

On a real Unreal Engine 5 project, expect anywhere from twenty minutes to several hours, depending mostly on shader compilation and how warm your derived data cache is. The first build is always the worst one. Set a build time limit so a genuinely hung build ends instead of holding your machine overnight.

Can I upload to Steam, Epic, and itch.io from one build?

Yes. One packaged build can go to all three, one at a time. If you enable auto-publish, a successful build uploads itself to every store you configured, in order, with anything half-configured skipped and explained rather than failing the run.

Is publishing included on the free plan?

Yes, on every plan including Free. Packaging runs on your machine with your engine, and uploads go from your machine to your store account, so there is nothing for us to meter.

What if I want builds to happen automatically on every commit?

That is USourceControl Forge, a separate app you install on a spare machine and enroll against your organization. It watches for commits, rebuilds the exact committed state, packages it, and publishes a downloadable release for your team, with optional Steam upload from the runner. It is on every plan too.

The build you ship should be the work you committed

Version your Unreal project, package it with your own engine, and send it to Steam, the Epic Games Store, or itch.io from the same window. Free for solo developers.

Create your first project