Salesforce

Salesforce OWD vs Sharing Rules: The Real Fix

Org-wide defaults set the floor. Sharing rules only add exceptions on top of that floor. If you remember one thing about the Salesforce sharing model, make it that: OWD closes access, sharing rules open it back up for specific groups, and neither one can undo what the other does. Most broken visibility tickets trace back to someone forgetting which direction each tool moves.

The confusion is understandable because both live in the same Setup menu and both sound like they control who sees what. But they solve opposite problems. OWD answers "what is the default access level for every record of this object, for every user who is not the owner?" Sharing rules answer "which specific group of users gets more than the default?" You cannot use a sharing rule to take access away. That single rule explains almost every sharing bug you will ever debug.

What Org-Wide Defaults Actually Control

Org-wide defaults, set under Setup > Sharing Settings, define the baseline visibility for every object: Private, Public Read Only, Public Read/Write, or Controlled by Parent. This baseline applies to every user who is not the record owner and has not been granted access some other way. Set Opportunity to Private and, by default, a rep in Chicago cannot see a rep's deal in Dallas. Set it to Public Read/Write and everyone sees and edits everyone's pipeline.

Most orgs start Private on sensitive objects like Opportunity, Case, and custom financial records, then use sharing rules and roles to widen access deliberately. That is the correct default posture. Starting wide and trying to lock down later means you are retrofitting security onto data that is already exposed, which is a much harder and riskier job than tightening a permissive setting from day one.

Role hierarchy also interacts with OWD, and this trips people up constantly. If OWD is Private, users above a record owner in the role hierarchy still see that owner's records by default, unless you explicitly uncheck "Grant Access Using Hierarchies" for a custom object. That checkbox exists specifically because custom objects do not inherit hierarchy access automatically the way standard objects do.

Sharing Rules Only Open Access, Never Close It

A sharing rule grants additional access to a group of users, a role, a role and subordinates, or a public group, based on record owner or a criteria match on the record. That is the entire job description. There is no sharing rule type that says "hide this record from these users." If you need to restrict, the only lever is OWD, or restricting field-level security and page layouts separately, which controls fields, not record visibility.

This is why widening OWD to fix one visibility complaint is almost always the wrong move. Say a manager cannot see a rep's Cases. The fix is a sharing rule scoped to that manager's role, not a change to org-wide defaults that exposes every Case to every user in the company. Sharing rules let you be surgical. OWD changes are blunt instruments that affect the entire object, everywhere, for everyone.

Criteria-based sharing rules are worth calling out specifically because they get underused. Instead of sharing by owner, you share by field value: all Opportunities where Region equals EMEA go to the EMEA public group, regardless of who owns them. That single rule replaces what would otherwise take dozens of owner-based rules as reps get hired, transferred, and terminated.

Manual Sharing and Apex Managed Sharing: The Escape Hatches

Manual sharing is the one-off button on a record's detail page that lets an owner or an admin share a single record with a single user or group. It is fine for exceptions: a contractor who needs one Opportunity for a quarter, a support case that needs a second pair of eyes. It does not scale, and it is not something you should ever build a process around, because it lives on the record itself and disappears if the record's owner changes in certain scenarios.

Apex managed sharing is the programmatic version, built for logic too complex for point-and-click sharing rules. It creates rows in the object's share table (OpportunityShare, CustomObject__Share) directly through code, and unlike manual sharing, it survives ownership changes and can encode conditions no declarative rule could express, like "share this record with everyone who worked a deal in the last 90 days regardless of current role." The tradeoff is that you now own that logic. Nobody in Setup can see it or edit it without opening the code.

How Salesforce Actually Calculates Final Access

Final record access is the union of every source that grants it. Salesforce checks all of these and grants the highest level found across any of them; nothing subtracts:

SourceWhat it does
Org-Wide DefaultSets the baseline for everyone not covered below
OwnershipOwner always has full access to their own records
Role HierarchyGrants access upward through management chain, if enabled
Sharing RulesGrants access to defined groups, owner-based or criteria-based
Manual SharingOne-off grants added directly on a record
Apex Managed SharingProgrammatic grants written to the object's share table
Teams (Account/Opportunity/Case)Grants access to named team members on that specific record

Because it is a union, you cannot debug a visibility problem by looking at just one setting. If a user cannot see a record, check every row in that table in order: is OWD too restrictive, is there a sharing rule that should apply but does not match its criteria, is the role hierarchy checkbox unchecked, is a team missing a member. The bug is almost never in more than one place, but you have to check all of them to find which one.

Common Mistakes That Break Record Visibility

The most common mistake is treating profiles as the sharing mechanism. Profiles and permission sets control object and field-level permissions: whether a user can read, create, edit, or delete Opportunities in general. They say nothing about which specific Opportunity records that user can see. A user can have full Modify All on Opportunity at the profile level and still see zero records if OWD is Private and no sharing rule reaches them. Object permissions and record sharing are separate systems, and conflating them wastes hours of debugging.

The second mistake is widening OWD as a quick fix. It works, technically, in the sense that the visibility complaint goes away. It also works by exposing every record in the object to every user, forever, which usually violates whatever compliance or confidentiality reason the object was Private in the first place. Nine times out of ten, the actual fix is a five-minute sharing rule, not an org-wide setting change that a security review will flag six months later.

The third mistake is forgetting that sharing rules cannot be retroactive in the way people expect. Add a new sharing rule and Salesforce recalculates access for existing records, which can take real time on large objects, sometimes hours in enterprise orgs with millions of rows. If you just added a criteria-based rule and users still cannot see qualifying records, check the Sharing Recalculation status before assuming the rule is broken.

When to Use Each Tool

Set OWD once, early, based on the most sensitive use case for that object, and revisit it rarely. Use owner-based sharing rules for the common case: a team or role needs access to records owned by another team or role. Use criteria-based sharing rules when access depends on a field value rather than who owns the record, like territory or product line. Reach for manual sharing only for genuine one-offs that do not justify a rule. Reach for Apex managed sharing only when the access logic cannot be expressed declaratively at all, and document it well, because it is invisible to anyone just browsing Setup.

Get the sequence right and the sharing model stays boring, which is exactly what you want from access control. Get it backwards, starting wide and trying to claw back access later, and you will spend years untangling exceptions nobody remembers the reason for.

Frequently Asked Questions

Can a sharing rule restrict access below the org-wide default?

No. Sharing rules only grant additional access on top of whatever the org-wide default allows; they cannot remove access from anyone. The only way to restrict record visibility below the current baseline is to change the org-wide default itself, or to remove a broader sharing rule that was granting extra access.

Why can a user with full Modify All permission still not see a record?

Modify All is an object-level permission from a profile or permission set, and it is separate from record-level sharing. If org-wide default is Private and no sharing rule, role hierarchy, or team grants that specific record to the user, they will see zero records despite having full edit rights on the object in theory. Object permissions and record sharing are two independent systems in Salesforce and both have to align for a user to actually see data.

How long does it take for a new sharing rule to apply to existing records?

Salesforce triggers an automatic sharing recalculation job when you add or edit a sharing rule, and on small objects it finishes in seconds. On large objects with millions of records, recalculation can take hours, and you can check its status under Setup in the Sharing Settings page. New records created after the rule exists get evaluated instantly; it is the backlog of existing records that takes time to reprocess.

What is the difference between owner-based and criteria-based sharing rules?

Owner-based sharing rules grant access based on who owns the record, for example sharing every record owned by the East Region role with a specific public group. Criteria-based sharing rules grant access based on a field value on the record itself, regardless of owner, such as sharing every record where Region equals EMEA. Criteria-based rules are usually more durable because they do not need updating every time ownership changes through staff turnover or reassignment.

When should I use Apex managed sharing instead of a standard sharing rule?

Use Apex managed sharing only when the access logic cannot be expressed through the declarative options in owner-based or criteria-based sharing rules, such as conditional access based on multiple related objects or time-based windows. It writes directly to the object's share table and survives ownership changes, unlike manual sharing done on an individual record. The tradeoff is that the logic lives in code, invisible to admins browsing Setup, so it needs clear documentation for anyone maintaining the org later.