Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
Diagram illustrating the process and structure of Apex Managed Sharing in Salesforce development
Apex

Apex Managed Sharing - When to Use It and How It Works

Sharing rules cover most record access requirements, and then one turns up that they cannot express. Apex Managed Sharing is how you grant that access in code, one Share row at a time.

The short answer

Apex Managed Sharing grants record-level access in code by inserting rows into standard and custom Share objects. Use it when the access rule cannot be built with declarative tools such as sharing rules, role hierarchies, or Flow.

Key takeaways Reserve Apex Managed Sharing for access logic that sharing rules, the role hierarchy and Flow cannot express. On custom objects, set the RowCause field to a custom Apex Sharing Reason so Salesforce does not remove the share when record ownership changes. Bulkify share record operations and batch large data volumes to stay inside governor limits and keep the org responsive. Delete the specific share records once the access is no longer required. Check the sharing logic in test classes by querying the target Share object with SOQL, for users who should get access and for users who should not.

When should you use Apex Managed Sharing?

You set up record access with the standard tools and they do not cover the case in front of you. That is where Apex Managed Sharing takes over. I still tell people to try sharing rules and the rest of the declarative toolbox first, but some business logic is too odd for a criteria-based rule.

In my experience you know it is time for code when the sharing decision depends on a related object or an external system. Maybe access has to expire after forty-eight hours. Maybe the team structure the business keeps describing does not map to the role hierarchy at all. If a Flow or a sharing rule cannot express the rule, Apex Managed Sharing can.

One caution: do not jump to code too fast. I have seen teams build a whole sharing engine and then realize a better role hierarchy would have done the job. Weigh the Apex vs Flow trade-off before you start writing Share records by hand.

How Apex Managed Sharing works in the real world

Every object that supports sharing has a Share object sitting next to it. A custom object called Project__c gets Project__Share. Standard objects get AccountShare, OpportunityShare and so on.

Apex Managed Sharing means inserting rows into those Share tables. Each row tells Salesforce to give one user or group one level of access to one record, and records why.

The four fields on a Share record

Four fields do the work when you build these records in code.

  • ParentId is the Id of the record you are sharing.
  • UserOrGroupId is the Id of the user or public group getting access.
  • AccessLevel is usually Read or Edit. Some objects allow All, which I use sparingly.
  • RowCause is the why. On custom objects, define your own Apex Sharing Reasons in the Setup menu.

Pro tip: on custom objects, never set RowCause to Manual in Apex. When the record owner changes, Salesforce deletes every Manual share automatically. A custom Apex Sharing Reason survives the owner change.

Writing the code: a practical example

Here is a snippet I have used plenty of times for sharing a custom object. Bulkify it before you point it at more than one record.


// Create a new share record for a custom object
Project__Share jobShare = new Project__Share();

// Set the record being shared
jobShare.ParentId = 'a01xx0000001Abc';

// Set the user receiving access
jobShare.UserOrGroupId = '005xx000001Xyz';

// Set the access level
jobShare.AccessLevel = 'Edit';

// Use a custom sharing reason defined in Setup
jobShare.RowCause = Schema.Project__Share.RowCause.Special_Project_Team__c;

insert jobShare;

Developers routinely forget the other half of this. When the access is no longer needed, something has to take it away. If a user leaves a project team, your code should find that share record and delete it.

Handling large data volumes

In an org with millions of records, be careful. Recalculating sharing across a huge table slows performance to a crawl. I have written before about managing Salesforce large data volumes, and sharing is a big part of that story. Insert thousands of share rows in batches and keep an eye on your limits.

Testing your sharing logic

Do not assume the share record was created and move on. Query the Share table in your test class and check. Plenty of people skip that step, and it comes back to bite them during a production deployment.

Create a test user, run your sharing logic, then run a SOQL query on MyObject__Share. A row count of zero means something is wrong. Test the negative case too: a user who should not have access should not end up with it.

Key takeaways

  • Use Apex Managed Sharing only when the declarative options (sharing rules, the hierarchy) fail you.
  • Always use a custom Apex Sharing Reason as the RowCause on custom objects, so shares are not deleted when the owner changes.
  • Bulkify your sharing logic. Inserting share records in a loop is a one-way ticket to Governor Limit hell.
  • Do not forget the cleanup. If the business logic says access is gone, your code needs to delete the share record.
  • Test by querying the Share objects in your test methods.

Apex Managed Sharing is a power tool, and it will cover almost any record access requirement a client throws at you. Reach for it when the declarative tools genuinely cannot do the job.

Frequently asked questions

When should you use Apex Managed Sharing in Salesforce?

Use Apex Managed Sharing when the access rule cannot be handled declaratively with sharing rules, the role hierarchy, or Flow. Common examples include sharing driven by related objects or external systems, temporary access windows, and custom team structures.

Why should you use custom Apex Sharing Reasons instead of manual sharing?

Salesforce deletes every share record with a Manual RowCause when record ownership changes. A custom Apex Sharing Reason keeps programmatically granted access on custom objects in place after an owner change.

What fields are required on a Share record in Apex?

A Share record needs ParentId for the target record, UserOrGroupId for the user or public group receiving access, AccessLevel for the permission such as Read or Edit, and RowCause for the sharing reason.

How do you test Apex Managed Sharing in test classes?

Run the sharing logic with a test user and query the matching Share object with SOQL to check the result. Confirm that the share records were created, and also that an unauthorized user does not receive access.

Newsletter

One email every Tuesday

New guides, tool updates, and the release-note changes that break things.

No spam. Unsubscribe in one click.

Comments

Loading comments...

Leave a Comment