Guide · Best practices

Game asset versioning best practices

The patterns that work, the mistakes to avoid, and the discipline that separates teams who lose work from teams who don't. For Unreal Engine teams.

11 min read

The core principle

Source control on a game project has one job: never lose work, ever. Everything else comes second. Speed, storage costs, workflow elegance. When a decision trades reliability for convenience, it's almost always the wrong trade.

That sounds obvious, but it's the thing teams forget when they skip locking, stop versioning, or trust that Google Drive will "probably be fine" for the texture folder.

What to commit, what to exclude

Commit source artifacts. Exclude derivatives.

Source artifacts are the files a human made or that are non-trivial to regenerate: .psd, .blend, .fbx, .wav, Unreal Blueprints and materials (.uasset), .umap levels, C++ source, config files.

Derivatives are files the engine or build system regenerates from source: Unreal's Saved/, Intermediate/, DerivedDataCache/, Binaries/, compiled shaders, build output. These don't belong in source control. They bloat storage and create spurious changes.

When in doubt: ask "if I deleted this file and reopened the project, would the engine rebuild it?" If yes, exclude it.

Naming assets for future-you

Asset naming gets a disproportionate amount of hand-wringing and not enough discipline. A few rules that pay off:

  • Stable names over descriptive names. Character_Boss_01 survives rework; FinalBoss_AngryDragon_v2_REAL_FINAL doesn't.
  • Prefix by type. T_ for textures, SM_ for static meshes, M_ for materials. Makes search and bulk operations tractable.
  • No versions in filenames. Version control versions files. Youshould not. If you're tempted to create character_v2.fbx, commit character.fbx and let history track versions.
  • Case consistency. Windows is case-insensitive, Linux (your CI) is not. Pick a case convention and stick to it.

Locking discipline

Binary files can't merge. Textures, FBX models, Unreal Blueprints, levels (.umap), materials, audio sessions: if two people edit concurrently, someone loses work.

The rule: lock before you edit binary files. Always.Even "just a quick tweak." Even when you're 99% sure no one else is in there.

Good locking habits:

  • Short, informative lock messages."wip balance pass L3, ETA 2h" is useful. "editing" is not.
  • Release locks at end of day, even if you're mid-work. Commit what you have, release, re-lock tomorrow. Dangling locks across time zones block teammates.
  • Use force-release sparingly. Admins can force-release, but doing it without asking the lock holder is a great way to lose trust and occasionally their work.

Commit hygiene

Teams that lose work usually lose it at commit time: sloppy commits, unreviewed changes, broken scenes pushed for the whole team to sync.

Habits that prevent trouble:

  • Commit working state, not "wip." If your scene doesn't open, don't commit it. The one exception: clearly-marked end-of-day backup commits.
  • One logical change per commit. Easier to understand in history, easier to roll back if it breaks something.
  • Readable messages."Added boss intro cutscene, wired up trigger" beats "stuff."
  • Review the file list before committing. Accidentally adding Unreal's Saved/ or Intermediate/ is the #1 way to balloon storage.

Backups and redundancy

Source control is your primary backup, but it's not your only backup. Good practice:

  • Commit often. A commit-per-day minimum for every team member. A commit-per-session is better.
  • Mark releases and milestones.When you ship a playtest build or hit a milestone, make a clearly-labeled milestone commit, with a message like "MILESTONE: Beta 1", so it's findable in history. Makes rollback trivial.
  • Off-site copies for critical milestones. For major milestones, download a local copy. One backup is no backup.
USourceControl stores every version automatically. Restoring to a prior state is a one-click operation. Use it freely when experiments go wrong.

Onboarding new team members

A new team member's first day decides whether they develop good source control habits or bad ones. Invest:

  1. Walk them through the first commit. Not just "here's the app, figure it out."
  2. Show them locking. Have them lock a file, edit it, commit, and see the lock release.
  3. Demonstrate rollback. Seeing "we can always get the old version back" changes how people work.
  4. Point them at the team's conventions: naming, folder structure, commit style.

Common antipatterns (and what to do instead)

"We'll add source control later." Adding source control after months of parallel work is painful. Start on day one, even if you're solo.

Saving everything in Dropbox. Dropbox has no locking, no meaningful version history, and creates conflict copies that ruin binary files. It is not source control.

"Just one more uncommitted change." Uncommitted work is unbacked-up work. Commit, or prepare to lose it.

Committing huge regenerable folders. Unreal's Saved/, Intermediate/, and DerivedDataCache/ aren't project state; they're cache. Exclude them.

Mixing personal config with project config. Per-user workspace files, .vs/, and .idea/ are personal. Exclude them from commits.

Frequently asked

What should I exclude from source control in an Unreal Engine 5 project?

Saved/, Intermediate/, DerivedDataCache/, Binaries/, Build/, .vs/, and *.VC.db. All of them are regenerated from source assets, so versioning them costs storage and produces noisy diffs without buying you anything. USourceControl excludes these by default. Content/, Config/, Source/, Plugins/, and the .uproject should always be included.

Should I commit packaged builds?

It depends on who needs them. If your playtesters or QA are not set up to build from source, committing packaged builds is the simplest distribution channel you have and every build stays recoverable. If everyone on the team builds locally, it is dead weight. Storage is unlimited either way, so the deciding factor is whether the artifact is useful to someone, not whether it fits.

How often should a game team commit?

At least daily, and always before you stop for the day. Game assets are binary, so a commit is a full snapshot rather than a diff, which means an uncommitted afternoon is genuinely unrecoverable if the drive fails. Commit at natural milestones during the day too: a finished asset, a working feature, a completed pass.

What makes a good commit message on an art-heavy project?

Say what changed and why, in the language of the game rather than the file system. "Retextured the market district stalls, warmer palette per art review" tells a teammate something in six months. "Updated assets" does not. This matters more on binary projects than on code, because nobody can read the diff to work out what you meant.

How should we name and organize game assets?

Pick a convention, write it down, and apply it from the first commit. Prefix by type (SM_ for static meshes, T_ for textures, BP_ for Blueprints, M_ for materials) and group by feature rather than by file type, so everything for one system lives together. Renaming binary assets later is expensive because history follows the path, so the cost of getting this wrong compounds.

Do these practices change with World Partition and OFPA?

The fundamentals hold, with one addition: the __ExternalActors__ and __ExternalObjects__ directories must be versioned, because after One File Per Actor those directories are your level. The .umap becomes a small shell holding grid and data layer settings. HLOD output is the one genuine judgment call, since it is derived data you can rebuild.

Build good habits from day one

Cloud source control for Unreal Engine 5 teams, from $25/user/mo. No server to run, and the right practices baked in.

Create your first project