Skip to content

The Same Share Record Without Code

Module 6 of 6 in the chapter Programmatic Sharing: Apex and Flow Managed Sharing, chapter 11 of Securing Salesforce: Sharing and Visibility. Each module stands on its own.

The question this module answers: How does a flow write and keep share records, and when should the share logic be a flow instead of Apex?

I remember the moment in class. I’d just shown an Apex share surviving an owner change, and a student asked: did you mention you can do this in flows now? Another student said they’d only used Apex sharing once or twice, because you have to write the trigger and maintain the logic. So I went looking, live, and found an article showing a Case Share record created by a flow. Look at that.

That’s why I stopped calling it Apex sharing. It’s programmatic sharing, because flows do it too. Chapter 5 showed the insert (Set 5, Programmatic). This module takes the whole design from module 5, two triggers, a recalculation and a plan for day zero, and builds it in Flow.

A share record doesn’t care who wrote it. Apex, a flow or an integration: the row in the share table is the same.

In a flow, it’s a Create Records element on the share object, Apple__Share for the apple. You fill in the same four pieces: the record’s ID, the user or group, the access level, and the row cause. And the row cause can be your own. Salesforce’s Developers blog says it directly: “You can also assign a custom row cause in Flow” (chapter 5 module 6). With a reason like Party, the shares stay when the owner changes, on custom objects and, since the October 2026 rollout, on standard objects too (module 3).

Removing shares is a Delete Records element on the same object. Filter it on your own row cause. The platform keeps its own rows, the owner’s and the rules’, but a flow that deletes every share it can find will take the manual shares people made, and other code’s shares, with it. Delete only what your logic wrote.

Here’s the question I’d ask any flow that touches sharing: whose access is it running with?

Salesforce answers it by how the flow starts. “By default, a flow runs in user context or system context, depending on how the flow is launched.” Record-triggered flows and schedule-triggered flows run in “System context without sharing.” Flows started from a button, a Lightning page or an Experience Cloud site run as the user (Flow Run Context (opens in a new tab), Salesforce Help, checked 2026-11-07).

For sharing, that’s mostly what you want. A record-triggered flow has to see every apple and every user to share them correctly, and System Context without Sharing “can access all data” (Set Flow Run Context (opens in a new tab), Salesforce Help, checked 2026-11-07). That’s also why it needs a reviewer. A flow running as the system can write a share to anyone. That’s the point, and it’s the risk.

A screen flow is different. It runs as the user, so it can only do what that user can do. A screen flow that lets people share a record is limited by their own access, and that’s usually right.

Module 5’s rule holds here too: write the share logic once, and call it from two places. In Flow, the logic is an autolaunched flow used as a subflow. Both record-triggered flows call it.

Here’s the outline, element by element. It’s the flow version of module 5’s AppleSharing class:

  1. Inputs: a collection of apples, and a collection of users. The flow on the apple passes in its one apple and the users the rules could give it to; the flow on the user passes in its one user and the apples the rules could give them.
  2. Get Records on Apple__Share: the shares for those apples and those users, where the row cause is Party.
  3. Delete Records: the shares from step 2. Only your reason, never Manual.
  4. Loop through the apples, and inside it through the users. A Decision asks whether the rules, in custom metadata, give this user this apple, and whether the user is active.
  5. Assignment: add a new Apple__Share record to a collection. Not a Create Records inside the loop.
  6. Create Records: the whole collection, once, after the loops.

Steps 5 and 6 matter. In my Flows class I say it plainly: watch your DML in the loops. A Create Records for each share, inside a loop, uses up the limits fast the first time apples arrive in bulk.

The flow on the apple is a record-triggered flow on Apple__c. It runs when an apple is created, or when a field the rules read changes, and calls the subflow.

The flow on the user is a record-triggered flow on User. It runs when a user is added, made active or inactive, or when a field the rules read changes, like a department or a region. But it hits the same wall as module 5’s user trigger. User is a setup object, and a share record isn’t, so they can’t be saved in the same transaction (module 5).

So the user flow writes its shares on an asynchronous path. Salesforce’s architects list this as exactly what the path is for: “Avoid mixed DML errors that occur when you update a value on a related record that isn’t part of the record that triggered a flow” (Asynchronous Processing on the Lightning Platform Decision Guide (opens in a new tab), Salesforce Architects, checked 2026-11-07). The path “runs in the background after the original record save is successfully committed.” One catch: “Asynchronous paths don’t support the ISCHANGED operator, for example in decision elements” (Record-Triggered Flow Considerations (opens in a new tab), Salesforce Help, checked 2026-11-07). Decide what changed in the flow’s start conditions, not on the path.

That’s not the only way. In my Flows class I mentioned that I’ve seen people handle mixed DML with platform events: one flow publishes an event, and another flow, started by the event, does the work in its own transaction. Either way, the shares arrive a moment after the user is saved.

The same design, built in Flow The same design, built in Flow. On the record: a record-triggered flow runs when an apple is created or changed, and creates records on Apple__Share with the row cause Party, a reason of your own. On the user: a record-triggered flow on User runs when a user is added or changed, and writes shares on an asynchronous path, in its own transaction, so there's no mixed DML error. When the rules change: a schedule-triggered flow deletes and rebuilds the Party shares, in batches of 200 records, up to 250,000 interviews in 24 hours. Day zero: a bypass, built first; a custom permission turns the flows off, the shares are loaded with Data Loader, then the flows are turned back on. Footnote: same share record, same reason, same two doors; only the tool changes. {"author": "Steve Simpson", "blueprint": "1.0.1", "builder": "standard 1.58.0", "built": "2026-11-04", "id": "DGM-SVA-PS-11", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "comparison 0.5.0", "theme": "stevetecharc 1.4.0"} On the record record-triggered flow Runs when an apple is created or changed Create Records on Apple__Share Row cause: your own reason, Party On the user record-triggered flow on User Runs when a user is added or changed Writes shares on an asynchronous path Its own transaction: no mixed DML error When the rules change schedule-triggered flow Deletes and rebuilds the Party shares Batches of 200 records Up to 250,000 interviews in 24 hours Day zero a bypass, built first A custom permission turns the flows off Load the shares with Data Loader Then turn the flows back on Same share record, same reason, same two doors. Only the tool changes. © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

The rules live in custom metadata, and someone changes them. Every share is now out of date, and no apple or user changed to tell a flow.

On a custom object, Salesforce’s recalculation button, the Apex Sharing Recalculation related list, takes an Apex class (module 5). There’s no flow version of that list. In Flow, the recalculation is a schedule-triggered flow: it runs on the apples, one interview per apple, and each calls the same subflow.

Know its limits before you rely on it. “By default, a schedule-triggered flow’s query retrieves records in batches of 200.” And: “The maximum number of schedule-triggered flow interviews per 24 hours is 250,000, or the number of user licenses in your org multiplied by 200, whichever is greater. Each record retrieved by the schedule-triggered flow’s query creates one interview.” It runs as the Default Workflow User set in Process Automation Settings, not as whoever changed the rules (Schedule-Triggered Flow Limits and Considerations (opens in a new tab), Salesforce Help, checked 2026-11-07).

Do the math. An org with 1,000 user licenses gets 250,000 interviews a day. A million apples is four days of recalculation. That’s when Apex batch, or a bulk load, starts to look better.

Here’s how I explain limits in my Flows class. When you insert an account, there might be five flows and an Apex trigger that all run. They don’t each get their own limits. It’s like my kids getting one bowl of snacks to share: one set of limits for the whole transaction. The first flow eats some, the next flow eats some, and the last one hits the limit and gets the error.

Sharing flows are often the hungriest in that bowl. They query users, query shares, delete and create. So keep them lean: filter early, collect the records and save them once, and know what else runs on the same object.

Module 5’s day zero still applies: a million accounts with 10 shares each is 10 million share records. A flow can do it, but slowly, and the scheduled flow’s daily limit makes it slower. Most teams load the share records directly.

And when you load, you don’t want your flows to fire. I tell my Flows class: you’re about to load a million records, and you need a bypass switch. Build it into all your flows before you need it, not the day before the load.

Salesforce’s architects say the same, and they say how. “A well-architected Salesforce organization requires a consistent and reliable mechanism to bypass automation. This is not an optional feature.” Their recommended way is custom permissions: “The modern, scalable standard for implementing bypass logic is custom permissions” (Record-Triggered Automation (opens in a new tab), Salesforce Architects, checked 2026-11-07). Each sharing flow checks it at the start, the load user gets it for the load, and then it’s taken away. Then run the recalculation once, so the shares match the rules.

So which should hold your share logic? Salesforce’s architects frame it by how busy the object is. “Record-Triggered Flow is the preferred solution for low automation density.” For more, “the hybrid pattern (Record-Triggered Flow with Invocable Apex),” and Apex “for Salesforce objects with high automation density, and for use cases that require high performance, sophisticated logic, or granular control over transactions.” And one rule I’d underline for sharing: “Use one entry point per Salesforce Object… Try to avoid mixing Flow and Apex triggers as entry points for the same Object” (Record-Triggered Automation).

For sharing, that comes down to a few questions:

  • How much else runs on the object? A quiet custom object is a good home for a flow. Account, with a dozen automations, probably already has an Apex trigger framework. Put the sharing there.
  • Who will maintain it? If admins will change the rules, a flow they can read is worth a lot.
  • How big are the volumes? Within the flow limits, a flow is fine. At a million records, Apex batch and bulk loads win.
  • Do you need the recalculation button? On a custom object, that’s an Apex class.
Flow or Apex for the share logic Flow or Apex for the share logic. A flow, when the logic is simple: few automations on the object, rules an admin can read and change, volumes inside the flow limits, and admins will maintain it. Apex, when the logic is heavy: many automations on the object, complex rules or very large volumes, a recalculation class on a custom object, and developers will maintain it. Footnote: one entry point per object, so don't put a flow and a trigger on the same object; a flow can call Apex for the heavy part. {"author": "Steve Simpson", "blueprint": "1.0.0", "builder": "standard 1.58.0", "built": "2026-11-03", "id": "DGM-SVA-PS-12", "rights": "\u00a9 2026 Twinshark LLC. All rights reserved.", "template": "comparison 0.5.0", "theme": "stevetecharc 1.4.0"} A flow when the logic is simple Few automations on the object Rules an admin can read and change Volumes inside the flow limits Admins will maintain it Apex when the logic is heavy Many automations on the object Complex rules or very large volumes A recalculation class on a custom object Developers will maintain it One entry point per object: don't put a flow and a trigger on the same object. A flow can call Apex for the heavy part. © 2026 Twinshark LLC · stevetecharc.com
Click to enlarge

Whichever you choose, the rest of this chapter still applies. A reason of your own, not Manual. Share with a bucket when you can (module 4). Two doors, the record and the user. A plan for when the rules change. And since Spring ‘26, the release update for asynchronous sharing names flows as well as Apex: a flow that adds someone to a group and then assumes they can see the records needs testing (module 5).

Test knowledge. Flows can write share records: Create Records on the share object, with a custom sharing reason as the row cause. Record-triggered and schedule-triggered flows run in system context without sharing by default. A flow on the User object can’t write share records in the same transaction; an asynchronous path avoids the mixed DML error. A likely area, not a known question.

  • Whether the share logic is a flow or Apex, by how busy the object is, who maintains it and the volumes, with one entry point per object.
  • The run context of every flow that writes or deletes shares, and who reviews it.
  • That every Delete Records on a share object filters on your own reason.
  • How the user flow runs in its own transaction: an asynchronous path or a platform event.
  • What recalculates the shares when the rules change, and how many days it takes at today’s volume.
  • The bypass: which custom permission turns the sharing flows off for a load, who gets it, and when it’s taken away.

Beyond the exam: what AI changes. AI can build a flow from a sentence now. Ask for “share apples with the right people” and you may get a record-triggered flow that works on the first day: one door, a Create Records inside a loop, no bypass, and no reason of its own. Ask it the same review questions: where’s the flow on the user, what deletes the old shares, what runs when the rules change, and what happens on a million records? And remember that an agent’s actions are often flows. A flow running in system context does the same for an agent as for a person. Chapter 20 covers agents.