💬 In plain
words: A Custom Permission is
a simple yes/no flag you attach to users, which your code and flows can check —
like a feature switch per person. Use it instead of hardcoding profile names in
logic.
📌 Example: Validation rule blocks editing closed Cases —
but the audit team must edit them. Create Custom Permission
'Edit_Closed_Cases', add NOT($Permission.Edit_Closed_Cases) to the rule, assign
it to auditors via a permission set. No profile checks in formulas.
🎬 Real-Life
Example: Bypassing a Validation Rule Imagine you have a
rule: no one can discount an Opportunity by more than 20%. But the VP of Sales
needs to override this rule when closing major deals.
The Old/Bad Way
(hardcoding): You write a validation
rule that checks the user's profile name: Discount__c > 0.20 &&
$Profile.Name != 'System Administrator' && $Profile.Name != 'VP of
Sales'.
Why this is bad: If you later decide that Regional Managers
should also get this power, you must rewrite the formula. If a user changes
roles, you must update their profile. It becomes a maintenance nightmare.
The New/Good Way
(Custom Permissions): 1. Create a Custom
Permission named Can_Approve_Large_Discounts.
2. Create a Permission Set called "Discount Approvers" and add
that Custom Permission to it. 3. Assign
the Permission Set to the VP of Sales — and anyone else who needs it. 4. Write the rule to look for the pass, not
the person: Discount__c > 0.20 &&
NOT($Permission.Can_Approve_Large_Discounts).
The payoff: The system no longer cares who the user is or
what profile they have. It only checks if they hold the "VIP pass". A
new manager needs the power? Assign the Permission Set. Done.
Concept
A Custom Permission is a named flag that you define, assign, and check. You can check it in Apex, in formulas, in validation rules and in flows. That decouples 'can this user do X' from checks on profile name or role. You assign it through permission sets and PSGs, covered in 1.2. You check it with $Permission.MyPerm in declarative places, and with FeatureManagement.checkPermission('MyPerm') in Apex. It is the maintainable answer to 'only certain users can override this rule'. Hardcoding profile names is brittle. Gating on a custom permission is portable and auditable. Custom Permissions are often bundled with Connected Apps, or shipped with a feature.
🧠Custom
Permission = named flag you CHECK, not a profile-name hardcode. $Permission.X
(formula/VR/flow) · FeatureManagement.checkPermission('X') (Apex). Assign via
permission set.
Core Q&A
Q: You need a validation rule
that everyone must pass EXCEPT a small group of override users. How do you
implement it maintainably?
🎯
Say this first: Create a Custom Permission. Check it in
the validation rule with $Permission. Assign it to the override group through a
permission set.
A: Define
a Custom Permission — call it 'Bypass_Amount_Limit'. Assign it through a
permission set to the users who may override. Then write the validation
rule so it fires only when NOT $Permission.Bypass_Amount_Limit. Common
mistake: hardcoding profile names in the rule. That breaks the moment a profile
is renamed or cloned, and it forces a rule edit every time the org grows. The
permission travels across profiles, and it audits cleanly — whoever holds the
permission set holds the permission. The same flag also gates Apex, through
FeatureManagement.checkPermission, and gates flows, so all three stay
consistent. Adding or removing an override user is one permission-set
assignment and zero rule edits.
//
Validation Rule formula:
// AND( Amount__c > 10000,
NOT($Permission.Bypass_Amount_Limit) )
// Apex
check:
if
(FeatureManagement.checkPermission('Bypass_Amount_Limit')) {
// allow the privileged path
}
Follow-ups (scenario-based)
Q1: Custom Permission vs a
checkbox on a Custom Setting vs checking the profile name — when each?
A1: Use
a Custom Permission to gate a capability per user. You assign it with permission
sets, and you can check it in code and in declarative tools. That is the
default answer to 'which users can do X'. Use a Hierarchy Custom Setting
checkbox when the override carries a value, and you need it at user, profile or
org level. Bypass switches are the classic case: 'skip automation for this
integration user'. It works in Apex and in validation rules through
$Setup — see 2.3. Checking the profile NAME: almost never. It breaks on rename
and on clone, and it does not travel. Simple rule: a capability is a Custom
Permission, a configuration value or a bypass is a Custom Setting, and profile
names are never hardcoded.
Q2: How do Custom Permissions
help package or feature-gate functionality?
A2: A Custom
Permission gives you a clean on/off gate that does not care who the user
is. The feature's code and its automation check the permission. Turning the
feature on for a user or an org is just an assignment, through a permission
set that can ship inside a package. That buys you three things. You can
deploy code dark — present, but gated off. You can roll out to a pilot group by
assigning the permission. And you can gate premium features in a managed
package, because Custom Permissions can be packaged and tied to
Permission Set Licenses. The pattern in one line: ship the capability, gate it
with a Custom Permission, control rollout by assignment. No code change turns a
feature on.
Q (compare): If we can assign a permission
set, why do custom permissions exist at all?