Not verified hands-on. This article was written from primary documentation rather than reproduced in an org, so it carries no tested-release badge. If you run it and something differs, say so in the comments and it gets tested and corrected.

In one sentence: build the permission sets first, assign them alongside the existing profile, prove nothing broke, and only then empty the profile out. Users move to a minimal profile last, one group at a time. Five things never leave the profile, so stop trying to migrate them: login hours, login IP ranges, default record types, page layout assignment, and the default app.

What a permission set genuinely cannot hold

Short list, and it decides your whole plan.

  • Login hours and login IP ranges. Profile-only, both. If your security team relies on profile login IP ranges, you will keep more than one profile forever, and that is fine.
  • Default record type. A permission set can make a record type available. It cannot say which one is preselected when the user clicks New.
  • Page layout assignment. Layouts are assigned by profile and record type. That single fact keeps most orgs on a handful of profiles rather than one.
  • The default app, and whether a tab is on by default rather than merely available.

Everything else belongs in sets: object and field permissions, system permissions, Apex and Visualforce access, custom permissions, record type availability, tab settings, connected app access and flow access.

The sequence that does not break anyone

Permissions are additive. Nothing subtracts except a muting permission set inside a group. That property is what makes a safe migration possible: you can run both models at once and measure the difference before removing anything.

  1. Freeze the profiles. No new grant goes on a profile. Announce it, because one well-meaning admin granting one field undoes weeks of work.
  2. Take a baseline you can diff against. Retrieve the profiles as metadata (sf project retrieve start -m Profile), and keep the XML in version control. The Setup UI is useless for comparison.
  3. Build baseline sets by capability. “Manage Cases”, “Read Accounts”, “Export Reports”. Small and reusable by more than one job role. If every set is used by exactly one group, you have rebuilt profiles with more clicks.
  4. Assign in parallel. Users keep their profile and gain the sets. Nobody can lose access at this step, which is the entire point of doing it this way.
  5. Strip the profile, one object at a time. Small batches, rollback file ready, and watch the support queue for a week between them.
  6. Move users to a minimal profile last, after you have recreated layout assignments, default record types and tab defaults on the target profile.

Step six is where people get hurt

Changing a user’s profile changes their page layouts, default record type and default app at the same instant. Minimum Access – Salesforce ships with almost nothing, and it has no layout assignments for your custom objects until you make them.

Do the layout work before the switch, not after. Assign every layout on the target profile for every record type, set the default record types, then move ten users and wait. The complaint you get should be about field ordering, not about access. That is the tell that the permission work was right.

Verify with queries, not with screenshots

Before and after each strip, capture what the profile actually grants:

SELECT Parent.Profile.Name, SobjectType, PermissionsRead, PermissionsEdit,
       PermissionsCreate, PermissionsDelete, PermissionsViewAllRecords
FROM ObjectPermissions
WHERE Parent.Profile.Name = 'Sales User'
ORDER BY SobjectType

Run it against the profile and against each permission set, then diff the results. Field permissions come from FieldPermissions the same way. Ten minutes to script, and it is the only evidence an auditor will accept.

How many profiles should you end up with

One per distinct combination of user licence, layout assignment, default record type and login restriction. Usually three to six, not thirty. Anything past that exists because somebody cloned a profile to change one checkbox.

Salesforce announced the retirement of permissions on profiles and then cancelled it. The direction did not change, only the deadline. Do this because a permission set is assignable, revocable and readable.

Frequently asked

Can a permission set take access away from a profile? No. Access is the union of profile and every assigned set. The only subtractive tool is a muting permission set, and it mutes only within its own permission set group.

Do I need permission set groups from the start? No, and starting with them tends to produce groups nobody can explain. Build clean capability sets first, then group the ones that always travel together.

What about permissions that need a permission set licence? Some only appear on a set tied to a permission set licence, and the licence assignment has to exist before the set behaves. Check this early for features like Sales Engagement.

Is it safe to delete the old profile? Only once no user is assigned and no layout assignment references it. Keep the XML in git and delete a month later.