
Andrew Hanna

Andrew Hanna

Short answer: put permission sets in source control as the real source of truth, decompose them so two people can edit them without a merge conflict, keep profiles thin and treat every profile deploy as an overlay rather than a full replacement. Then deliberately stop tracking the parts that are environment-specific, because most profile churn in a repo is noise nobody reads.
Two documented behaviours make profiles behave unlike every other file in your repo.
Put those together and the same profile produces a different diff depending on who retrieved it and what else was in their package. That is why profile diffs are the most argued-about, least trusted files in most Salesforce repositories.
Salesforce had announced that permissions in profiles would be retired starting in Spring '26. On 6 June 2026 that enforcement was cancelled, citing customer feedback and remaining feature gaps, while Salesforce continued to recommend a permission-set-led security model (Salesforce Help).
The practical read: the deadline is gone, the direction is not. Profiles stay supported, so nobody has to panic-migrate, but if you are choosing where to invest your source-control discipline, invest it in permission sets. They are additive, they decompose, and they merge.
A permission set as retrieved is one large XML file listing every object, field and user permission. Two admins touching two unrelated fields collide in the same file. Salesforce ships a fix for this in the CLI: source behavior options that split the file into one file per permission group (Salesforce DX developer guide).
sf project convert source-behavior --behavior decomposePermissionSetBeta2
--dry-run.
sfdx-project.json is updated so the behaviour
sticks for everyone, and the existing source is converted in place.
The same mechanism covers custom labels, workflows, sharing rules and external service registrations. Note the gap: profiles are not on the decomposable list. Objects and object translations decompose by default, the rest are opt-in betas, and profiles remain a single file.
Half the pain here is self-inflicted. These belong outside the repo, or behind a deliberate exclusion.
Write the exclusions down as a rule in the repo, not as tribal knowledge in one person's CLI history. A rule that lives in someone's shell alias is a rule that breaks the first time a new joiner runs a retrieve.
Never do steps three and four in the same release. Additive and subtractive permission changes have completely different rollback stories, and mixing them is how a Monday morning lockout happens. More release engineering playbooks are in our SF Guides library.
Should profiles or permission sets be the source of truth?
Permission sets. They are additive, they decompose into mergeable files and Salesforce recommends a permission-set-led model. Keep profiles for baseline defaults such as license, default record types and page layouts.
Are permissions in profiles being retired?
No. The retirement planned for Spring '26 was cancelled on 6 June 2026. Migration is now your own timeline rather than a deadline.
Why does my profile diff change when I did not touch it?
Because a profile retrieve only returns settings for the metadata included in the same request. Change the package contents and the file changes. Fix the retrieve manifest, not the file.
Can profiles be decomposed like permission sets?
Not today. The CLI source behavior options cover permission sets, custom labels, workflows, sharing rules and external service registrations. Profiles remain one file, which is another argument for keeping them thin.
Commitment free!