The CustomPermission metadata type defines a custom security capability or feature toggle that can be assigned to users through PermissionSet or Profile metadata. Introduced in API version 31.0, CustomPermission is the gold-standard architectural pattern for replacing hardcoded $Profile.Name checks across ValidationRule formulas, Flow decisions, ApexClass logic, and LightningComponentBundle UI controls.
In Salesforce DX projects, custom permissions are stored in force-app/main/default/customPermissions/ with the .customPermission-meta.xml suffix.
Key Metadata Fields
| Field | Type | Required | Description |
|---|---|---|---|
label |
string |
Yes | Human-readable label shown in Setup and Permission Set editors |
description |
string |
No | Explains what business capability or bypass this permission grants |
isLicensed |
boolean |
No | Indicates whether the permission requires a managed package license (v38.0+) |
connectedApp |
string |
No | Associates the custom permission with a specific ConnectedApp |
requiredPermission |
CustomPermissionDependencyRequired[] |
No | Declares prerequisite <customPermission> dependencies (dependency set to true) |
Production-Grade XML Example
Below is a CustomPermission definition (Bypass_Account_Validation.customPermission-meta.xml) used to exempt data migration jobs from validation rules:
<?xml version="1.0" encoding="UTF-8"?>
<CustomPermission xmlns="http://soap.sforce.com/2006/04/metadata">
<description>Exempts the running user from Account and Contact validation rules during bulk data loads.</description>
<isLicensed>false</isLicensed>
<label>Bypass Account Validation</label>
</CustomPermission>Checking CustomPermission Across the Stack
1. Validation Rules and Flows ($Permission)
AND(
NOT($Permission.Bypass_Account_Validation),
ISBLANK(BillingCountry)
)2. Apex (FeatureManagement.checkPermission)
public with sharing class OrderApprovalService {
public static void approveHighValueOrder(Order ord) {
// Zero-SOQL, session-cached permission evaluation
if (!FeatureManagement.checkPermission('Approve_Executive_Discounts')) {
throw new AuraHandledException('You lack permission to approve executive discounts.');
}
ord.Status = 'Approved';
update as user ord;
}
}3. Lightning Web Components (@salesforce/customPermission)
import { LightningElement } from 'lwc';
import hasExecutiveDiscountPerm from '@salesforce/customPermission/Approve_Executive_Discounts';
export default class DiscountApprovalAction extends LightningElement {
get isApproveButtonDisabled() {
return !hasExecutiveDiscountPerm;
}
}Auditing Custom Permissions with SOQL
Both CustomPermission and SetupEntityAccess are queryable in standard SOQL:
-- 1. List all Custom Permissions in the org
SELECT Id, DeveloperName, MasterLabel, NamespacePrefix, Description, IsLicensed
FROM CustomPermission
ORDER BY DeveloperName ASC
-- 2. Find every Permission Set that grants a specific Custom Permission
SELECT Id, Parent.Name, Parent.Label, Parent.IsOwnedByProfile, SetupEntityId
FROM SetupEntityAccess
WHERE SetupEntityType = 'CustomPermission'
AND SetupEntityId IN (
SELECT Id FROM CustomPermission WHERE DeveloperName = 'Bypass_Account_Validation'
)Tip
Testing Custom Permissions in Apex Unit Tests: Instead of querying and assigning profiles in @TestSetup, assign a lightweight Permission Set containing your CustomPermission to a test user via insert new PermissionSetAssignment(AssigneeId = u.Id, PermissionSetId = ps.Id); inside System.runAs(u).
Frequently asked questions
Why should I use CustomPermission instead of checking Profile.Name in Validation Rules or Apex?
Hardcoding Profile.Name breaks when organizations migrate to a Permission Set-led security model or rename profiles. Checking a CustomPermission decouples your code and formulas from specific Profiles and allows granular, time-bound assignment via Permission Sets.
How do I check a CustomPermission in Apex without consuming a SOQL query?
Call FeatureManagement.checkPermission('Permission_API_Name') in Apex. It evaluates the running user's active session permissions in memory and consumes zero SOQL queries.
How do I check a CustomPermission inside a Lightning Web Component?
Import the custom permission from the @salesforce/customPermission/Permission_API_Name module in your LWC JavaScript file. It returns true if the current user has the permission and undefined otherwise.
What does the requiredPermission field on CustomPermission do?
The requiredPermission array defines child or prerequisite CustomPermissions that must also be enabled whenever a parent CustomPermission is assigned in a Permission Set or Profile.
How do I query which Permission Sets grant a specific CustomPermission?
Query SetupEntityAccess where SetupEntityId matches the CustomPermission Id and SetupEntityType equals CustomPermission, joining ParentId to PermissionSet.
Comments
Questions, corrections and tips are welcome. Comments are GitHub Discussions, so you sign in with GitHub.