If your org-wide defaults (OWD) are restrictive and you need dynamic, record-by-record access, Apex Sharing in Salesforce lets you grant access programmatically. This guide explains Understanding Apex Managed Sharing, Sharing a Record Using Apex, RowCause / reasons, how to share to roles and subordinates, and key Apex sharing limitations—with working code you can paste into your project.
What is Apex Managed Sharing (and why/when to use it)?
Apex managed sharing allows developers to grant record access in code using an object’s …Share table (for example, AccountShare). It complements click-based sharing (OWD, role hierarchy, sharing rules, teams, manual) when your access logic depends on complex runtime conditions (lookups, thresholds, custom workflows), or when you need to keep access synchronized as data changes.
When to use Apex sharing in Salesforce
- Criteria that standard sharing rules can’t express (e.g., cross-object or per-record logic).
- You need to attach a durable “reason” to a custom object share and recalc it later.
- Automations that keep access aligned with business roles/ownership beyond teams and rules.
Share objects, fields, and Apex sharing RowCause / reason
Each shareable object has a Share object:
- Standard: AccountShare, ContactShare, CaseShare, etc.
- Custom: YourObject__Share
On AccountShare, key fields include:
- AccountId, UserOrGroupId (user, queue, or Group),
- AccountAccessLevel (Read, Edit, All = Full Access),
- child object access: OpportunityAccessLevel, CaseAccessLevel.
RowCause (Apex sharing reason):
- Explains why the share exists (e.g., Owner, Manual, Rule, or a custom Apex sharing reason for custom objects). Only manual/custom (Apex) shares are editable in code.
- Custom Apex sharing reasons can be created only for custom objects (Setup → Object → Apex Sharing Reasons). Standard objects don’t support custom reasons; use Manual.
Why we use Apex sharing in Salesforce: to enforce nuanced, runtime access beyond what OWD, rules, and teams can reliably model—while keeping an auditable Apex sharing reason on custom objects.
Example 1 — Apex sharing in Salesforce example
(dynamic Account share)
Use case: When an Account is inserted, give the user in a lookup field read or edit access based on Annual Revenue.
trigger AccountShare_OnInsert on Account (after insert) {
List<AccountShare> shares = new List<AccountShare>();
for (Account a : Trigger.new) {
if (a.Share_Record_To_User__c == null) continue;
AccountShare s = new AccountShare();
s.AccountId = a.Id;
s.UserOrGroupId = a.Share_Record_To_User__c; // 005... user or 00G... group
s.RowCause = Schema.AccountShare.RowCause.Manual; // standard object
s.AccountAccessLevel = (a.AnnualRevenue != null && a.AnnualRevenue >= 5000000)
? 'Edit' : 'Read';
s.OpportunityAccessLevel = 'Read';
s.CaseAccessLevel = 'Read';
shares.add(s);
}
if (!shares.isEmpty()) insert shares;
}
This is Sharing a Record Using Apex via the object’s Share table. For Accounts, you can also control related Opportunity and Case access as part of the same share.
Example 2 — How to give sharing access to roles and subordinates
(and internal subordinates)
To share with a Role (or Roles and Internal Subordinates), you don’t put a UserRole.Id into UserOrGroupId. You share to the Group that represents that role scope:
// Find the Group for a Role (Role or RoleAndSubordinates / RoleAndSubordinatesInternal)
Group rGroup = [
SELECT Id, Type, RelatedId
FROM Group
WHERE Type IN ('Role','RoleAndSubordinates','RoleAndSubordinatesInternal')
AND RelatedId = :[SELECT Id FROM UserRole WHERE DeveloperName = :'<ROLE_API_NAME>' LIMIT 1].Id
LIMIT 1
];
AccountShare s = new AccountShare();
s.AccountId = '<ACCOUNT_ID>';
s.UserOrGroupId = rGroup.Id; // 00G...
s.AccountAccessLevel = 'Read';
s.RowCause = Schema.AccountShare.RowCause.Manual;
insert s;
- The Group object’s Type identifies Role vs. Role + Subordinates.
- For external-sharing compatibility, Salesforce now refers to the target as Roles and Internal Subordinates; review and update any old “roleAndSubordinates” references in code.
Apex records sharing vs standard record sharing
- Standard record sharing = OWD + role hierarchy + sharing rules + teams + manual shares (clicks).
- Programmatic sharing using Apex = you insert/delete rows in …Share to grant or revoke access, ideal for granular, dynamic logic. Architecture-wise, these create explicit grants that Salesforce combines with group membership to compute access.
For a narrative walk-through, see https://sfdc247.com/2025/09/exploring-salesforce-tooling-api-a-comprehensive-guide-for-developers.html
How and when to use Apex managed sharing to create durable access on custom objects
For custom objects, define Apex Sharing Reasons, use them in YourObject__Share.RowCause, and (optionally) register a Recalculation class to rebuild shares after events like OWD changes or lock conflicts. Only users with Modify All Data can add or change these Apex-managed shares.
FAQ
- Apex sharing reason for standard objects You can’t create custom reasons on standard objects—use RowCause = Manual.
- How to create Apex sharing reason in Salesforce On the custom object, open Apex Sharing Reasons → New, then reference it in code as Schema.Object__Share.RowCause.My_Reason__c.
- Apex sharing RowCause values you’ll see: Owner, Manual, Rule, and your custom reasons (custom objects). Some system-generated reasons are read-only.
- Apex sharing in Salesforce example See the Account sample above; on custom objects use ParentId, UserOrGroupId, AccessLevel, RowCause = Schema.My__Share.RowCause.My_Reason__c.
- How to give sharing access to roles and subordinates … Query the Group with Type of Role, RoleAndSubordinates, or RoleAndSubordinatesInternal, then share to that Group.Id.
- Apex sharing limitations
- Custom-object only for Apex managed reasons/recalc; standard objects can’t have custom reasons.
- Only users with Modify All Data can add/change Apex-managed shares on custom objects.
- When OWD becomes more permissive (e.g., Private → Public Read Only), Salesforce may remove redundant manual/Apex shares during recalculation.
- Excessive explicit grants can impact performance; architect groups/rules wisely.
Closing tips
1) Prefer groups (public groups/roles) over user-by-user shares to control share volume.
2) Always bulkify share logic and handle duplicates/idempotency.
3) On custom objects, couple shares to a clear Apex sharing reason and wire up recalculation for resilience.
By following these steps, you can quickly determine the last refresh date of a sandbox and the creation date of a production org in Salesforce. Running these queries in Production ensures accurate and up-to-date information.
Also Read – https://sfdc247.com/2020/06/flosum-vs-autorabit-vs-copado-the-best-salesforce-devops-release-management-tool.html
If you have any questions regarding Salesforce DevOps, I can guide you and clear all your doubts. you can always comment and contact me from our contact us page we will try to answer your queries as soon as possible and in case you have any suggestion on how to improve my website page, do reach out to me.
We also write product reviews on the tools and if you have any product that you would like to get reviewed you can always comment, contact me via Contact Us Page and I will reply back you immediately
#Note: Publishing this content anywhere without the consent of SFDC247 will result in a lawsuit against copyright infringement