The pattern: identify the business-logic gate, create the Custom Permission, reference it in code, assign through a permission set named after the role. The cost is one Custom Permission record plus one code reference; the benefit is admin-managed access without redeploying code for assignment changes.
- Identify the business-logic gate that needs admin-controlled access
A validation rule that should bypass for certain users, a Flow that should branch for senior approvers, an Apex method that should run for specific roles. The candidate is any access decision currently hardcoded.
- Create the Custom Permission
Setup, Custom Permissions, New. Name per convention (purpose-driven: Bypass_Discount_Validation, Senior_Approver, Access_Beta_Feature).
- Reference the Custom Permission in code
Apex: FeatureManagement.checkPermission. LWC: import from @salesforce/customPermission. Flow: $Permission reference. Validation Rule: $Permission reference.
- Create or extend a permission set with the Custom Permission
Name the permission set after the business role (Renewal Manager, Senior Approver). Include the Custom Permission in the set's System Permissions, Custom Permissions section.
- Assign the permission set to the right user population
Bulk assign via Setup or via a Flow that triggers on user attribute changes. Document the assignment criteria.
- Test with users in and out of the assigned population
Confirm the code path fires for assigned users and skips for unassigned. Sandbox first; production behavior should match.
- Document the Custom Permission and code references
Name, purpose, code references, permission sets that include it. The inventory is what saves future admins from forensics.
Purpose-driven, convention-based. The API identifier code references.
Permission set named after business role; includes one or more related Custom Permissions.
Apex FeatureManagement.checkPermission, LWC import, Flow $Permission, Validation Rule $Permission.
Name, purpose, code references, holding permission sets. Required for maintainability.
Test both with and without the permission to confirm the code branches correctly.
- Custom Permissions assigned through profiles work but break the modern permission-set-first pattern. Default to permission-set assignment.
- Without assignment, no user holds the Custom Permission. Creating the Custom Permission and forgetting the permission set assignment is a common omission.
- Code that checks a Custom Permission and finds nobody has it executes the no-permission branch. Test both branches; the unassigned branch needs to be correct, not just the assigned one.
- Custom Permissions accumulate without documentation. The inventory is the discipline that prevents permission sprawl.
- Pick platform-native permissions when they exist. Custom Permissions are the right tool when no platform construct fits; using them for things the platform already supports adds unnecessary configuration.