A tester messages you at 11pm: "the double jump is broken, I fall through the floor in the second room." You open the project, play the second room, double jump forty times. Nothing. You ask which build they were on. They say "the latest one." The latest one from the Discord channel, or the one you dropped in the shared drive on Tuesday, or the one your artist exported from their own machine with the unmerged animation branch still in it?
That bug report is now worthless. Not because the tester did anything wrong, but because the build had no identity. Every hour of playtesting you run against anonymous builds is an hour of data you cannot act on.
Build identity is the cheapest process a small team can adopt and the one most often skipped, because it feels like engineering hygiene rather than design work. It isn't. Your playtest notes, your bug list, your balance tuning and your milestone sign-offs all point at a build. If the pointer is vague, everything attached to it rots.
Pick a version scheme and stop thinking about it
The goal is not elegance. The goal is that any human can read a version string out loud over voice chat and any other human can find exactly that build.
| Scheme | Example | Good for | Weakness |
|---|---|---|---|
| Semantic versioning | 1.4.2 |
Shipped games, plugins, APIs | Pre-release games have no stable public API to version against |
| Date-based | 2026.10.13 |
Nightly internal builds | Two builds in one day collide; says nothing about content |
| Milestone + increment | 0.7.3 |
Projects organised around milestones | Needs a defined milestone list |
| CI build number | #412 |
Automated pipelines | No human meaning on its own |
| Milestone + CI number | 0.7.3-412 |
Small teams running playtests | Slightly longer to say |
For a team of two to ten people in production, the last row is the sweet spot. 0.7.3-412 tells you the milestone phase (0.7 = vertical slice polish), the iteration inside it (.3), and the exact unique build (412) that can never be reused. The number after the dash should come from a counter that only ever goes up — your CI server, or a plain integer you bump in a file at export time. Never let it reset.
Write the rule down in one line in your documentation so the next person does not invent a second scheme: milestone.minor.patch-buildnumber, build number monotonically increasing, never reused, never reset.
Put the version where you cannot avoid seeing it
A version that lives only in a filename will be lost the moment someone renames the zip. Stamp it in at least four places:
- Bottom-right corner of the screen, in a small, semi-transparent label, on every non-release build. This single change means every screenshot and every clip a tester sends you is self-identifying.
- The log filename, e.g.
game_0.7.3-412_2026-10-13_2114.log. - Save files, as a field in the header. When a save stops loading, you want to know which build wrote it.
- Your first telemetry event of the session, so analytics can be sliced by build.
The watermark is the one that pays for itself fastest. A tester's phone photo of a monitor becomes usable evidence.
The build manifest: five fields, two minutes
Every build you hand to another human needs a short record. Five fields are enough:
- Version —
0.7.3-412 - Date and platform —
2026-10-13, Windows x64 - Source — branch and commit hash, or the changelist number
- What changed — three to six bullets in player-facing language
- Known issues and what to test — the part everyone skips
"What changed" should not be a dump of commit messages. fix npe in PlayerController tells a tester nothing. Double jump now has a 6-frame buffer after leaving a ledge tells them exactly where to poke.
"What to test" is the field that converts a build into a playtest. Without it, five testers all replay the tutorial and nobody touches the new boss phase. With it, you write "Focus: boss phase 2 only. Ignore placeholder audio and the missing minimap." and you get five reports about the thing you actually changed.
This is also why build records belong next to your design work rather than in a separate engineering tool. If you keep a build list in GameDesignerX's build tracking module, each build sits in the same workspace as the playtest sessions, bugs and milestones that reference it — so "which build was the economy rebalance in?" has one answer instead of three guesses in three channels.
Make the build ID mandatory on every bug
One rule, enforced without exception: a bug report with no build ID is not a bug report. Put the field first in your template, not last.
Build: 0.7.3-412
Platform: Windows 11, RTX 3060
Steps: 1. Load chapter 2 2. Double jump into the left wall at the gate
Expected: Player lands on the ledge
Actual: Player clips through the floor, falls into the void
Frequency: 4 out of 5 attempts
Attachments: clip.mp4, game_0.7.3-412_...log
The payoff arrives the first time you need to find when something broke. With numbered builds and recorded manifests you can bisect: the bug is in 412 and not in 405, so you have seven builds to search and each one took you minutes to check. Without them, you are reading three weeks of commits with no way to confirm whether any given state ever actually produced the bug. The same discipline turns your bug tracker into history you can query — "every crash reported against builds 400-412" is a meaningful question; "every crash in October" is not.
Cadence: how often to cut one
Three tiers cover almost every small project:
- Internal build — daily or on every merge. Automated if you can, exported by one person if you can't. Purpose: catch breakage within a day of causing it.
- Playtest build — weekly, on a fixed day. Fridays work because you get weekend sessions back. Must have a full manifest and a "what to test" focus.
- Milestone candidate — once per milestone. Gets a full pass of your release checklist, gets archived permanently, and is the only kind of build you show to a publisher or put in front of press.
Keep the last ten internal builds and every milestone candidate forever. Storage is cheap; being unable to reproduce the build you demoed to a publisher six weeks ago is not.
A pre-handoff checklist
Run this before any build leaves your machine. It takes two minutes and prevents most wasted playtest sessions.
- Version number bumped and visible in-game
- Built from a committed, pushed revision — no local-only changes
- Launches on a machine that is not yours, from a clean folder
- No debug menu, god mode, or dev console bound to a key a tester might press
- Placeholder content that will confuse testers is either removed or listed in known issues
- Manifest written, including the "what to test" focus
- Archived somewhere permanent before it is shared
Failure modes to watch for
"Final" in a filename. game_final_v3_REALfinal.zip is a confession that you have no versioning. Numbers only.
Rebuilding the same version. If you fix one line and re-export, that is a new build number. Two different executables sharing a version string will cost you a day of confusion eventually.
Building from uncommitted work. The single most expensive habit on a small team: the one build that reproduced the bug exists only in a folder on a laptop that has since been reformatted.
A manifest nobody reads. If your testers do not know where the manifest lives, write it in the same message as the download link, every time.
None of this is glamorous, and none of it changes your game's design. What it changes is how much of your playtesting survives contact with the following week. A build with a name, a number, a changelog and a focus question turns five hours of volunteer play into evidence. A build called "latest" turns it into anecdotes.