Resources /
Blog

How to Deploy Profile Metadata in Salesforce Without Breaking Permissions

Submit your details to get a book

5
Min Read
Resources /
Blog

How to Deploy Profile Metadata in Salesforce Without Breaking Permissions

Download

Submit your details to get a book

5
Min Read
rendering of a profile

To deploy profile metadata in Salesforce, retrieve the profile with every related object, field and component named in the same package.xml, review the resulting XML, validate against the target org, then deploy. The behaviour that decides whether this goes well is simple to state and widely misunderstood: profile deployment is an overlay. Permissions present in the file are applied, and permissions absent from it are left exactly as they are in the target org.

That single rule explains why profiles are risky, why a retrieved profile is not a backup, and why deleting a line from the XML does not revoke anything.

What Is Profile Metadata in Salesforce?

A profile is an XML file defining what its assigned users can see and do. The main nodes are:

  • objectPermissions: create, read, edit, delete, view all and modify all per object.
  • fieldPermissions: readable and editable per field.
  • userPermissions: system-level flags such as API Enabled.
  • loginHours and loginIpRanges: when and where users can sign in.
  • Visibility settings: applicationVisibilities, tabVisibilities, recordTypeVisibilities, classAccesses, pageAccesses and flowAccesses.

These stack on org-wide defaults and the role hierarchy, and a single flag can override broader rules. Granting Modify All on Opportunity bypasses sharing for every user on that profile. Profiles apply to all their assigned users at once, which is why Salesforce now recommends permission sets for incremental access and profiles as a thin baseline.

How Salesforce Profile Retrieval Works

Profile retrieval is scoped by your manifest, and this surprises almost everyone the first time. When you retrieve a profile, the returned file includes security settings only for the other metadata types referenced in the same retrieve request. User permissions, login IP ranges and login hours are the exceptions and always come back.

Retrieve Profile on its own and you get a nearly empty file: user permissions and login settings, and essentially nothing else. No object permissions, no field permissions, no tab or record type visibility. The profile in your project directory looks complete because it is valid XML, but it represents a fraction of the real profile.

To retrieve object and field permissions, name those objects in the manifest alongside the profile:

XML
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <!-- The profile itself -->
    <types>
        <members>Sales User</members>
        <name>Profile</name>
    </types>

    <!-- Name every object whose permissions you need returned -->
    <types>
        <members>Account</members>
        <members>Opportunity</members>
        <members>Invoice__c</members>
        <name>CustomObject</name>
    </types>

    <!-- Apex class access requires the classes -->
    <types>
        <members>InvoiceController</members>
        <name>ApexClass</name>
    </types>

    <!-- Flow access requires the flows -->
    <types>
        <members>Invoice_Approval</members>
        <name>Flow</name>
    </types>

    <version>64.0</version>
</Package>

The same rule applies to every other section. Apex class access requires the classes in the manifest, page access requires the pages, and flow access requires the flows. Miss one and that node simply will not appear, with no warning that anything is absent.

This is why a retrieved profile is not a profile backup. It is a partial extract shaped by whatever you happened to request. Treating it as a restore point means discovering during an incident that it never contained the permissions you need back. Retrieval scope can also differ between source-tracked and non-source-tracked sandboxes, so check what you actually received rather than assuming parity between environments.

What each manifest actually returns

The effect is easiest to see by comparing three retrievals of the same profile:

  • Profile only. Returns userPermissions, loginHours and loginIpRanges. No object permissions, no field permissions, no tab or record type visibility. The file is small enough that its incompleteness is obvious once you know to look.
  • Profile plus CustomObject entries. Adds objectPermissions and fieldPermissions for those objects only. Objects you did not name are absent, and their permissions in the target org remain whatever they already were.
  • Profile plus ApexClass, ApexPage and Flow entries. Adds classAccesses, pageAccesses and flowAccesses. Flow access in particular is a common surprise: teams retrieve a profile, see no flowAccesses node, and conclude the profile grants no flow access, when in fact they simply did not ask for it.

The practical habit is to check the retrieved file against what you expected before you edit anything. If a node you intended to change is missing, the problem is your manifest, not the profile.

Risks of Salesforce Profile Deployment

Deployment follows the opposite rule to retrieval, and the combination is where teams get hurt.

Deployment is an overlay. Salesforce applies what is in the file. What is absent is not touched. There are three states, and only two of them do anything:

State in the profile XMLWhat it looks likeWhat happens on deployUse it to
EnabledThe node is present with the permission set to trueThe permission is granted in the target orgGrant access
DisabledThe node is present with the permission set to falseThe permission is revoked in the target orgRevoke access. This is the only way to remove a permission
OmittedThe node is absent from the file entirelyNothing. The target org keeps whatever it already hadLeave a permission untouched, and scope a deployment to only what you intend to change

Profile deployment is an overlay: Salesforce applies what is present and ignores what is absent. Deleting a node from the XML does not revoke the permission.

The most dangerous consequence is silent over-provisioning. You cannot revoke access by deleting a line from the profile XML. Delete a fieldPermissions node, deploy, and the deployment succeeds while the permission remains exactly as it was in the target org. Teams that expect removal by omission believe they revoked access when they did not, and nothing surfaces the gap. Unlike a lockout, which generates support tickets within minutes, over-provisioning stays invisible until an audit finds it.

To revoke a permission, set it explicitly to false and include it in the deployment.

The other real risks:

  • Unintended expansion. A bad merge that flips a read permission to edit, or adds modifyAllRecords, grants that access to every user on the profile the moment it deploys.
  • Missing dependencies. Referencing an object, field or record type that does not exist in the target fails the deployment, or applies partially.
  • Dependent permission ordering. Some permissions require others. Removing them in the wrong order fails validation.
  • License restrictions. Permissions unavailable to the target org’s licenses cannot be applied, creating source and target mismatches.

These are compliance problems as much as operational ones. Over-provisioned profiles undermine SOX segregation of duties, and excess field access works against GDPR data minimisation.

Prerequisites for Deploying Profile Metadata

Capture and Store Snapshots

Capture a complete snapshot of every profile before changing anything, and make sure it is complete rather than a manifest-limited extract. This is your rollback point, and its value depends entirely on its scope.

Compare Source and Target Orgs

Diff the profile XML between orgs so you know exactly which nodes differ. Pay attention to what is absent from your retrieved file as well as what differs, since absence means unchanged rather than removed and can hide a difference you intended to deploy.

Enforce Peer Review and Approval

Have security or compliance stakeholders review the diff. They will catch over-provisioned rights such as an unintended Modify All that a technical reviewer skims past. Document the approval so there is a record of who authorised the change.

Validate in a Full Sandbox

Validate in a sandbox that mirrors production configuration, using a validate-only run to confirm the deployment compiles and passes tests without changing anything.

Address License Restrictions Before Deployment

Confirm the target org’s licenses support every permission in the file. A permission valid on one user license may not exist on another, and the Metadata API will not always tell you clearly why it did not apply. Two checks are worth making explicitly: that the target org has the same edition-dependent features enabled, since permissions tied to features the target lacks cannot be set, and that the profile’s associated user license matches between source and target, because a profile tied to a different license type will behave differently even where the XML looks identical.

Document any manual post-deployment steps and attach them to the release record, so a permission that had to be applied by hand is visible at audit rather than living only in someone’s memory.

How to Deploy Profile Metadata in Salesforce: 5 Techniques

1. Define the Required Metadata Scope

Scope determines everything. Decide which permissions you intend to change, then build a manifest containing the profile plus every object, field, class, page and flow whose permissions you need represented. Retrieve with that manifest, confirm the resulting XML contains the nodes you expected, and deploy only what you intend to change. Anything you leave out stays as it is in the target.

2. Choose the Right Deployment Method

  • Salesforce CLI and Metadata API: full control over manifest scope and file contents, scriptable and repeatable. You track dependencies yourself. Always run a validate-only deployment first.
  • Change sets: deploy profile settings only for components included in the change set, with no diff view, no validation against source control and no selective control over individual nodes. Workable for small, well-understood changes; poor for anything involving many permissions. See the limitations of change sets.
  • External CI/CD tools: offer diffing and selective deployment, but stage metadata outside Salesforce, which raises data residency questions for regulated orgs.

3. Deploy Natively in Salesforce with Flosum

Flosum runs inside Salesforce, so profile XML never leaves the platform. You compare nodes side by side, select only the permissions you changed, and roll back from a snapshot held in the same org. This is the Flosum-specific option rather than native Salesforce behaviour; everything above works without it.

4. Consider Permission Sets for Flexibility

Where you can, grant new access through permission sets rather than expanding profiles. The blast radius is smaller, the intent is clearer at audit, and revoking access means removing an assignment rather than editing XML and hoping the overlay behaves as you expect.

5. Validate Dependencies Before Deployment

Confirm every referenced object, field, record type, class and flow exists in the target org before deploying. Check dependent permission ordering too, since some permissions cannot be removed while others that rely on them remain enabled.

Salesforce Profile Metadata XML Example

This extract shows all three states in one file. Note the difference between the granted permission, the explicitly revoked one, and what is simply not present:

XML
<?xml version="1.0" encoding="UTF-8"?>
<Profile xmlns="http://soap.sforce.com/2006/04/metadata">

    <!-- ENABLED: grants edit access to this field -->
    <fieldPermissions>
        <field>Invoice__c.Amount__c</field>
        <readable>true</readable>
        <editable>true</editable>
    </fieldPermissions>

    <!-- DISABLED: explicitly revokes access.
         This is the ONLY way to remove a permission. -->
    <fieldPermissions>
        <field>Invoice__c.Margin__c</field>
        <readable>false</readable>
        <editable>false</editable>
    </fieldPermissions>

    <!-- OMITTED: Invoice__c.Notes__c does not appear anywhere
         in this file. Its permissions in the target org are
         left exactly as they are. Deleting a node does NOT
         revoke the permission. -->

    <objectPermissions>
        <object>Invoice__c</object>
        <allowRead>true</allowRead>
        <allowCreate>true</allowCreate>
        <allowEdit>true</allowEdit>
        <allowDelete>false</allowDelete>
        <viewAllRecords>false</viewAllRecords>
        <modifyAllRecords>false</modifyAllRecords>
    </objectPermissions>

</Profile>

Post-Deployment Validation, Monitoring, and Rollback

Validate Immediately After Deployment

Run smoke tests using sentinel accounts that mirror your critical roles. Walk the workflows most likely to break: creating a lead, converting an opportunity, running an integration. Check both directions, confirming that access you intended to grant works and that access you intended to revoke is actually gone.

Use Automated Checks and Analytics

Compare pre- and post-deployment permissions to confirm only the intended changes landed. Review Login History for insufficient privileges errors, and use Event Monitoring where available. The permission comparison matters most: it is the only reliable way to catch a revocation that did not take effect.

Layer in Manual Verification

Spot-check field-level security, object permissions, tabs, login hours and IP ranges for the profiles that matter, and have power users from finance, sales and support run their normal workflows. Document the checks as audit evidence.

Maintain Recovery-Ready Snapshots

Commit every profile change to version control or capture an immutable snapshot before promotion, and make sure the snapshot is complete rather than manifest-limited.

Execute Fast, Targeted Rollbacks

Rolling back a profile means redeploying the previous state, which is subject to the same overlay behaviour. If your change granted access, the rollback file must explicitly set those permissions back to false; removing them from the file does nothing.

Communicate and Verify Post-Rollback

Alert the incident channel, name an owner, notify affected business leads, and retest under multiple personas before closing. Compare permissions against the pre-deployment baseline rather than assuming the rollback was complete.

Common Profile Deployment Errors

“Manage Cases requires delete permission.” A dependent permission ordering problem. Removing Delete and Modify All on Case while Manage Cases is still enabled fails validation. Split it into two deployments: remove the dependent permission first, then the underlying ones.

Permissions you removed are still present after a successful deployment. Expected behaviour, not a bug. You deleted the nodes instead of setting them to false. Re-deploy with the permissions explicitly present and set to false.

Permissions missing from a retrieved profile. The related metadata type was not in your manifest. Add the objects, fields, classes, pages or flows and retrieve again.

Unexpected permissions enabled on a newly deployed profile. Deploying an entirely new profile can inherit settings from the target org’s Standard User profile. Deploy new profiles in two passes: the profile first, then its full permission set.

Deployment fails on a missing component. The profile references an object, field or record type that does not exist in the target. Deploy the dependency first.

Profile Deployment Checklist

  1. Build a manifest containing the profile plus every related component whose permissions you need.
  2. Retrieve, then confirm the XML actually contains the nodes you expected.
  3. Capture a complete snapshot of the target profile as a rollback point.
  4. Diff source against target and review what changed and what is absent.
  5. Set any permission you intend to revoke explicitly to false rather than deleting it.
  6. Confirm every referenced component exists in the target org.
  7. Get security or compliance review, and record the approval.
  8. Run a validate-only deployment against the target.
  9. Deploy, then verify both the grants and the revocations took effect.
  10. Compare post-deployment permissions against the pre-deployment baseline.

Manage Profile Deployments with Flosum

Profile deployments are difficult because the platform’s retrieval and overlay behaviour make it easy to hold an incomplete file and easy to believe a change took effect when it did not. Flosum addresses that with node-level comparison between orgs, approval workflows with an audit history of who authorised each permission change, and snapshot-based rollback held inside Salesforce so profile XML never leaves the trust boundary.

For teams under SOX, GDPR or FedRAMP obligations, the audit trail matters as much as the deployment itself. Book a demo to see how controlled profile comparison and recovery work in practice.

Frequently Asked Questions (FAQ)

How do I deploy Profile metadata in Salesforce?
Build a package.xml containing the profile plus every object, field, class, page and flow whose permissions you need, retrieve with that manifest, and confirm the returned XML contains the nodes you expected. Review the changes, set any permission you intend to revoke explicitly to false, run a validate-only deployment against the target org, then deploy and verify both grants and revocations took effect.
What is Profile metadata in Salesforce?
Profile metadata is the XML representation of a Salesforce profile, defining what assigned users can access. It contains object permissions, field permissions, user permissions such as API Enabled, login hours and IP ranges, and visibility settings for apps, tabs, record types, Apex classes, pages and flows. Profiles apply to every assigned user simultaneously, which is what makes deployment changes high impact.
Why are field permissions missing from my retrieved Profile?
Because profile retrieval is scoped by your manifest. A retrieved profile only includes security settings for the other metadata types named in the same retrieve request. User permissions, login IP ranges and login hours always come back, but object and field permissions only appear if you also requested those objects and fields. Add them to package.xml and retrieve again.
Does Salesforce remove Profile permissions omitted from XML?
No. Profile deployment is an overlay: Salesforce applies what is present in the file and leaves what is absent untouched. Deleting a node from the profile XML does not revoke the permission in the target org, and the deployment will succeed while the access remains in place. This is the most common misconception about profile deployments and a frequent source of silent over-provisioning.
How do I deploy a disabled Profile permission?
Include the permission in the file and set it explicitly to false. For a field, that means a fieldPermissions node with readable and editable set to false. For an object permission, set the relevant flag such as allowDelete or modifyAllRecords to false. Removing the node instead leaves the existing permission untouched, because absence means unchanged rather than revoked.
What should be included in package.xml with a Profile?
Every metadata type whose permissions you need represented. Objects and fields for object and field permissions, Apex classes for class access, Visualforce pages for page access, flows for flow access, record types for record type visibility, apps for app visibility, and tabs for tab visibility. Anything you leave out simply will not appear in the retrieved profile.
Can I deploy Profiles with Salesforce Change Sets?
Yes, though it is rarely the best choice. Change sets deploy profile settings only for the components included in the change set, and they offer no diff view, no validation against source control and no control over individual permission nodes. For anything beyond a small, well-understood change, the Metadata API through Salesforce CLI or a DevOps platform gives you far more visibility into what will actually change.
How do I roll back a Salesforce Profile deployment?
Redeploy the previous profile state from a complete snapshot or version-controlled file. Remember that rollback is subject to the same overlay behaviour: if your change granted permissions, the rollback file must set those permissions explicitly to false, because removing them from the file will not revoke them. Verify against your pre-deployment baseline rather than assuming the rollback was complete.
Table Of Contents
Author
Stay Up-to-Date
Get flosum.com news in your inbox.

Thank you for subscribing