Software versioning in Software Configuration Management (SCM) is the practice of assigning consistent versions to files and builds so teams can trace artifacts, reproduce releases, and avoid upgrade breakage. This guide is for build engineers, release managers, and developers who want a practical scheme they can enforce in CI and setup processes.
Originally published on 2012-05-23; fully revised and updated.
This rewrite is based on guidance attributed in the original article to The Build Master: Microsoft’s Software Configuration Management Best Practices. See the original post for historical context.

Why versioning matters in SCM
A reliable versioning scheme helps teams answer critical questions quickly: What source produced this binary? Can we rebuild that release? Is this upgrade safe? The source material highlights these operational benefits.
- Trace product binaries back to source and ownership.
- Re-create previous builds using meaningful labels or tags.
- Reduce component conflicts (historically called “DLL hell”).
- Support setup, upgrades, and service pack workflows.
- Help support and QA identify exactly which bits are running.
A practical four-part file version format
The original guidance recommends a four-part file version pattern:
major.minor.build.revisionCode language: CSS (css)
Version fields and typical ownership
| Field | Typically assigned by | How often it changes | Primary purpose |
|---|---|---|---|
| Major | Component or product owner | Rarely during a release cycle | Internal product line or major release identity |
| Minor | Component or product owner | Rarely during a release cycle | Incremental release indicator |
| Build | Build or release automation | Every build | Uniquely identifies generated artifacts |
| Revision | Build or servicing team | Usually during servicing | Patch, hotfix, or replacement context |
Build number strategy: incremental counters vs date stamps
The source explicitly recommends a simple n = n + 1 build number for each released build. The main reason is clarity when you have multiple releases on the same day.
| Strategy | Example | Strengths | Weaknesses | Fit with source guidance |
|---|---|---|---|---|
| Incremental counter | 100, 101, 102 | Simple ordering, unique per build, easy rollback discussions | Needs persistent counter storage | Recommended |
| Date-based only | 20261013 | Human-readable date | Ambiguous for multiple same-day builds | Not recommended |
| Date plus suffix | 20261013.2 | Distinguishes same-day builds | Convention drift and parsing inconsistency risk | Use only if governance is strict |
Where versioning fits in the build and release workflow
flowchart TD
A[Code merged to main] --> B[CI starts build]
B --> C[Build counter increments]
C --> D[Artifacts get version stamp]
D --> E[Tests run]
E --> F{Release approved}
F -- no --> G[Fix and rebuild]
F -- yes --> H[Publish package]
H --> I[Installer compares existing versions]
I --> J[Upgrade only when candidate is newer]
This flow keeps source control, build identity, and deployment behavior aligned. Without this alignment, support teams lose traceability and upgrades become risky.
Example: stamping version values in CI
The following examples show a minimal pattern: persist a build counter, construct major.minor.build.revision, then stamp artifacts.
MAJOR=4
MINOR=2
PREV_BUILD=$(cat .ci/build-counter)
BUILD=$((PREV_BUILD + 1))
REVISION=0
VERSION="$MAJOR.$MINOR.$BUILD.$REVISION"
printf "%s\n" "$BUILD" | tee .ci/build-counter
printf "%s\n" "$VERSION" | tee build/version.txt
echo "Building version: $VERSION"Code language: JavaScript (javascript)
steps:
- name: Compute version
run: ./scripts/compute-version.sh
- name: Build
run: ./scripts/build.sh "$(cat build/version.txt)"
- name: Publish metadata
run: ./scripts/publish-metadata.sh "$(cat build/version.txt)"Code language: JavaScript (javascript)
# Example: inspect a built DLL file version
(Get-Item ".\bin\MyComponent.dll").VersionInfo.FileVersionCode language: CSS (css)
Installer rules that reduce component conflicts
The original article focuses heavily on setup behavior in Windows component ecosystems. The core principle is still useful: an installer must make deterministic, version-aware decisions.
- Install OS-specific and locale-specific components correctly.
- Avoid writing shared binaries into system directories unless performing an approved system-component update.
- Do not overwrite newer components with older ones.
- If files are in use, schedule copy on reboot to avoid mixed old/new states.
- Register components correctly when registration is required.
- Keep recoverable backups of overwritten components when feasible.
- Distribute a controlled installer package rather than loose raw component files.
- Test setup on clean systems and on realistic machines with existing software.
Best practices checklist
- Define one organization-wide version format and document ownership of each field.
- Use a monotonic build counter for released builds.
- Stamp every artifact and publish version metadata with each pipeline run.
- Make installer overwrite logic explicitly version-aware.
- Test upgrade and rollback paths as first-class release criteria.
I’m Rajesh Kumar, a DevOps, SRE, DevSecOps, Cloud, and Platform Engineering expert passionate about sharing practical knowledge, real-world experiences, and industry best practices. I have worked at Cotocus and regularly write about technology, travel, investing, health, product reviews, and digital marketing through my various platforms.
I publish technical articles at DevOps School, travel stories at Holiday Landmark, stock market insights at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at TrueReviewNow, and SEO and digital marketing strategies at Wizbrand.
Find Trusted Cardiac Hospitals
Compare heart hospitals by city and services — all in one place.
Explore Hospitals