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

When should you use Apex Managed Sharing?

Look, we’ve all been there. You’re trying to set up record access and the standard tools just aren’t cutting it. That’s usually when you turn to Apex Managed Sharing to handle the heavy lifting. While I always tell people to stick to the guide to Salesforce sharing rules and declarative tools first, sometimes your business logic is just too weird for a standard criteria-based rule.

In my experience, you’ll know it’s time for code when you need to share records based on complex logic that lives in a related object or an external system. Maybe you need to grant temporary access that expires after forty-eight hours, or perhaps you’re dealing with a complex “team” structure that doesn’t map to the role hierarchy. If you can’t do it with a Flow or a sharing rule, Apex Managed Sharing is your best friend.

But a word of caution: don’t jump to code too fast. I’ve seen teams build massive sharing engines only to realize they could have solved it with a better-designed role hierarchy. Always weigh the Apex vs Flow options before you start writing Share records manually.

How Apex Managed Sharing works in the real world

Every object in Salesforce that supports sharing has a “Share” object sitting right next to it. If you have a custom object called Project__c, its partner is Project__Share. For standard objects, it’s things like AccountShare or OpportunityShare. It’s pretty straightforward once you get the hang of it.

When you use Apex Managed Sharing, you are essentially inserting rows into these Share tables. Each row tells Salesforce: “Give this User (or Group) this specific level of access to this specific record, and here’s why.” It’s surgical and precise.

The anatomy of a Share record

When you’re building these records in your code, you’ll be working with four main fields. Get these right, and the rest is easy:

  • ParentId: This is the ID of the record you’re actually trying to share.
  • UserOrGroupId: The ID of the person or the public group getting the keys to the kingdom.
  • AccessLevel: Usually “Read” or “Edit”. Some objects allow “All”, but use that sparingly.
  • RowCause: This is the “Why”. For custom objects, you’ll want to define your own Apex Sharing Reasons in the Setup menu.

Pro tip: Never use “Manual” as your RowCause in Apex if you’re working with custom objects. If the record owner changes, Salesforce wipes out all “Manual” shares automatically. Using a custom Apex Sharing Reason ensures your hard-earned access stays put.

Writing the code: A practical example

So what does this actually look like? Here’s a snippet I’ve used plenty of times to handle sharing for a custom object. It’s not fancy, but it gets the job done. Just remember to bulkify this if you’re doing it for more than one record at a time.


// 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;

Now, I’ve seen some developers forget that Apex Managed Sharing doesn’t just happen in a vacuum. You also need to think about what happens when that access is no longer needed. If a user leaves a project team, your code should be smart enough to find that specific share record and delete it. It’s all about keeping the house clean.

Handling Large Data Volumes

If you’re working in an org with millions of records, you need to be careful. Recalculating sharing for a massive table can bring your performance to a crawl. I’ve written before about managing Salesforce large data volumes, and sharing is a huge part of that. If you’re inserting thousands of share rows, do it in batches and keep an eye on your limits.

Testing your sharing logic

You can’t just assume the share record was created and call it a day. In your test classes, you need to actually query the Share table to verify it worked. It’s a step a lot of people skip, and it usually comes back to bite them during a production deployment.

Create a test user, run your sharing logic, and then run a SOQL query on MyObject__Share. If the row count is zero, you’ve got a problem. Also, make sure to test the “negative” side – if a user shouldn’t have access, make sure they don’t.

Key Takeaways

  • Only use Apex Managed Sharing when declarative rules (Sharing Rules, Hierarchy) fail you.
  • Always use custom Apex Sharing Reasons (RowCause) for custom objects to prevent shares from being deleted on owner changes.
  • Bulkify your sharing logic. Inserting share records in a loop is a one-way ticket to Governor Limit hell.
  • Don’t forget the cleanup. If the business logic says access is gone, your code needs to delete the share record.
  • Test thoroughly by querying the Share objects in your test methods.

At the end of the day, Apex Managed Sharing is a power tool. It gives you the flexibility to handle almost any security requirement a client throws at you. Just make sure you’re using it because you have to, not just because you like writing code. Keep it simple, keep it clean, and your future self (and your teammates) will thank you.