Automated Package Versioning (Limited Preview)
This feature is in limited preview — it is available to selected customers only, and behaviour and commands may change based on feedback. Reach out to the flxbl team if you would like early access.
This feature is available in sfp-pro and requires an sfp server, as the server keeps track of the last published version of each package per branch.
Version numbers in sfdx-project.json are a constant source of friction in team development. Every pull request that touches a package potentially fights over the versionNumber field, developers forget to bump versions (or bump them incorrectly), and there is no structured way to express whether a change is a patch, a minor or a major.
Automated package versioning takes the version number out of the day-to-day workflow. Packages you opt in are marked with the sentinel version 0.0.0.NEXT in sfdx-project.json, and the version of every artifact is computed at build time from:
The last published version of the package, tracked by the sfp server per branch
The intent of the changes since then — derived from your conventional commit messages, explicit
version:commit footers, or/versioncomments on pull requests
// sfdx-project.json — a server-managed package
{
"path": "src/sales",
"package": "sales",
"versionNumber": "0.0.0.NEXT"
}With this in place, merging a pull request titled feat(sales): add discount calculation and building produces the next minor version of sales automatically — if the last published version was 2.4.1, the new artifact is 2.5.0.<build>. The version field stays constant in source control, so pull requests no longer conflict on it.
How a version is computed
For every package that is part of a build, the version pipeline runs the following stages:
User override — if the package's
versionNumberis anything other than0.0.0.NEXT, that version is used verbatim (with the build number substituted into the fourth segment) and all other stages are skipped. This is what keeps packages you have not opted in behaving exactly as before.Explicit intent — a
/versioncomment on a merged pull request, or aversion:footer in a commit message, declares the bump explicitly. Explicit intent always wins over inference.Smart defaults — the conventional commit prefixes of the commits since the last published version decide the bump:
feat:is a minor,fix:(and everything else) is a patch, andfeat!:or aBREAKING CHANGE:footer is a major. Across multiple commits, the highest intent wins.Dependents expansion — when a change declares
dependents:<intent>, the direct dependents of the changed packages are also given a version bump and added to the build.Promoted version guard — for unlocked packages, if the current version series has already been promoted, a patch is automatically escalated to a minor, since Salesforce does not allow patching a promoted series.
Compute — the intent is applied on top of the last published version.
A few examples, assuming sales was last published as 2.4.1:
fix(sales): correct rounding on totals
2.4.2.<build>
feat(sales): add discount calculation
2.5.0.<build>
feat(sales)!: rework pricing API
3.0.0.<build>
fix(sales): small fix and feat(sales): new feature
2.5.0.<build> (highest wins)
chore: update labels (no recognised prefix)
2.4.2.<build>
Merged PR carrying the comment /version sales:major
3.0.0.<build>
The computed versions are displayed during every build:
After a successful publish, the new version is recorded on the server and becomes the base for the next build's computation.
What does not change
Packages you have not opted in are untouched. Any package with an explicit version (
2.4.1.NEXT) keeps its classic behaviour — its version is used as-is, and a manual version bump still triggers a rebuild. You can run a project with a mix of managed and manual packages indefinitely.Builds never fail because of versioning. Invalid intents are skipped with a warning, and if the server is temporarily unreachable, the build falls back to the versions recorded in your git tags.
How dependencies are treated
A bump never propagates on its own. Changing
core-crmdoes not bump the packages that depend on it. Dependent packages are only bumped when a change explicitly asks for it withdependents:<intent>(in a commit footer or a/versioncomment).Expansion is single-level.
dependents:patchoncore-crmbumps the packages that directly depend oncore-crm— not their dependents in turn. A package reachable through several dependency paths is bumped once, from its own last published version.Bumped dependents are built. A dependent that receives a version bump is added to the build so an artifact exists for the new version, even though its own source did not change.
Dependency version references are not rewritten. Entries in a package's
dependenciesarray (for example"versionNumber": "1.0.0.LATEST") are left for you to manage; unlocked package dependencies use minimum-version matching, so a bump in a dependency does not invalidate them. Raising a reference after a major change in a dependency remains a deliberate, manual decision.
Where to go next
Adopting automated versioning — enabling the feature and onboarding your packages
Expressing version intent — conventional commits,
version:footers and/versionPR comments, with examplesVersioning across branches — how parallel branches, merges and release lines behave
Last updated
Was this helpful?