Relationships Have Consequences
Also in 28 languages
Español · 日本語 · Português (Brasil) · Français · Deutsch · Italiano · 한국어 · 简体中文 · Português (Portugal) · 繁體中文 · Bahasa Indonesia · Türkçe · Polski · Tiếng Việt · ไทย · Nederlands · العربية · עברית · Українська · हिन्दी · Русский · Svenska · Dansk · Norsk bokmål · Suomi · Español (México) · Français (Canada) · Deutsch (Schweiz)

Module 7 of 10 in the chapter Salesforce Data Architecture, chapter 3 of the Data Architect course. Each module stands on its own. Previous: Fields Are Architecture Too · Next: Ownership and Lifecycle
The question this module answers: What am I really choosing when I connect two Salesforce objects?
Drawing a relationship is easy. In chapter 2 we drew lines and named them: a Retail Partner sends many manifests, a delivery carries many items, crews and trucks meet in a Crew Assignment. We talked about cardinality, optionality and history. Now we implement those lines on Salesforce, and a line on a diagram starts carrying a lot more weight.
When I choose a relationship type on Salesforce, I’m not just saying these two records are connected. I may also be deciding who owns the child, whether it can exist without the parent, who can see it, what happens when the parent is deleted, whether it can move to another parent, whether I can summarize it onto the parent, and what happens when there are hundreds of thousands of children. A relationship isn’t just a line. It carries behavior.
Start With the Business Relationship
Section titled “Start With the Business Relationship”Before lookup or master-detail, go back to the business. Take a Delivery and its Delivery Items, the refrigerator, the install, the haul-away. Can an item exist without its delivery? No. If the delivery is deleted, should its items go too? Yes. Do the items need their own owner or their own security? Not really. Should anyone move an item from one delivery to another? Hopefully not by accident.
Now take a Delivery and the Route it’s on. The delivery exists before it’s routed, it can be moved to another route when the plan changes, and deleting a route should never delete the deliveries on it. Two one-to-many lines that look the same on a diagram, with completely different behavior. Notice we still haven’t said “lookup” or “master-detail.” Describe the behavior first. The configuration implements it.
The Relationship Types
Section titled “The Relationship Types”Open the New Field screen and Salesforce offers you a handful of relationship types (Object Relationships Overview (opens in a new tab)):
- Lookup: links two objects. The meat and potatoes of Salesforce relationships.
- Master-detail: a parent-child binding where the parent controls the child.
- Many-to-many: not a field type of its own, but a pattern: a Salesforce Junction Object, a custom object with two master-details.
- Self-relationship: a lookup from an object to itself.
- Hierarchical: a special lookup that exists only on the User object, such as a user’s manager.
- External lookup and indirect lookup: the relationships to and from external objects, the
__xobjects from module 4. An external lookup points to a parent external object; an indirect lookup points from an external object to a standard or custom object, matched on a unique External ID.
Most of your design time goes to the first three. Let’s take them one at a time.
Lookup: These Records Are Connected
Section titled “Lookup: These Records Are Connected”A lookup says: this record is associated with that record. The child keeps its own identity, its own owner and its own life. A Delivery points to its Route. If the route is cancelled, the deliveries don’t vanish; they go back to be routed again.
It’s funny: the lookup field goes on the child, but the parent gets something too, a related list of its children. So when you create one, name both ends. The Related List Label is what people see on the parent, and the Child Relationship Name is what developers and integrations use to walk from parent to children. Don’t accept the defaults.
A lookup can be required or optional. When it’s optional, you decide what happens if the record it points to is deleted, and there are three choices (Considerations for Object Relationships (opens in a new tab)):
- Clear the value of this field, the default. The child stays, with an empty lookup.
- Don’t allow deletion of the lookup record. Try to delete the route, and Salesforce says no: it’s part of a relationship.
- Delete this record also, a cascade delete, like a master-detail. It’s only offered for a custom lookup on a custom object, it’s disabled by default, and Salesforce has to turn it on for your org, because a cascade delete bypasses security and sharing: users can delete records they couldn’t even see.
That’s a lifecycle decision hiding in a setup screen.
Lookup filters narrow what a user can pick. Say Delivery has an Installer lookup to Contact, and installers are one record type of contact among many. A lookup filter shows only installers, and it can filter on the current record, on the record being looked up, and on the user: their profile, role or permissions (Lookup Filters (opens in a new tab)). It’s a cheap way to keep a lookup honest.
Master-Detail: This Child Belongs to That Parent
Section titled “Master-Detail: This Child Belongs to That Parent”Master-detail makes a much stronger statement. In class I call it a very tight binding. You can’t have a detail without its master; the master field is required. The detail loses its own Owner field and inherits the owner of its parent. There’s no separate share table for the detail, so you can’t share a child on its own; it inherits its parent’s sharing. That’s why a detail object can’t have sharing rules, manual sharing or queues: they all need an Owner field (Object Relationships Overview (opens in a new tab)). In Setup its sharing setting reads Controlled by Parent. And on the master-detail field itself you choose a Sharing Setting: whether a user needs Read Only or Read/Write access to the master to create, edit or delete its details. Deleting the master deletes its details. And the master gets roll-up summary fields.
So if Delivery Item is a detail of Delivery, I’m saying: this item belongs to this delivery for its whole life. That’s the question I want answered before anyone picks Master-Detail Relationship in Setup.
The Delete Question
Section titled “The Delete Question”Here’s my favorite way to find out whether we’ve thought it through: what should happen to the children if somebody deletes the parent? Everybody gets uncomfortable. Good. Now we’re doing architecture.
A Retail Partner has hundreds of thousands of historical deliveries. Somebody deletes the partner. Should the deliveries disappear? Almost certainly not: the claims, the billing and the history all depend on them. Maybe deleting a partner shouldn’t be allowed at all, and the partner should be deactivated instead. With master-detail, deleting the master cascades to the details and their details; undeleting the master brings them back (Considerations for Object Relationships (opens in a new tab)). So when somebody says “master-detail gives us roll-ups,” my answer is: great. What else did you just agree to?
Ownership Comes Along for the Ride
Section titled “Ownership Comes Along for the Ride”With a lookup, the child can have its own owner. With master-detail, it can’t; access follows the master. That’s exactly right if the detail really is part of the parent. But if the child needs its own owner, its own sharing or its own lifecycle, the model is telling you master-detail is the wrong choice. The next module goes deeper into ownership, and the Sharing and Visibility course goes further still. For now: relationship design and security design aren’t separate conversations. The data model shapes the security model before anyone writes a sharing rule.
Required Parent, or Optional?
Section titled “Required Parent, or Optional?”Can the child exist before we know its parent? It matters more than it sounds. If deliveries arrive on the manifest the night before and routes are built afterwards, a required Route on Delivery would mean routing has to happen before the record can even be created. The physical relationship has to support the real lifecycle. So I don’t design relationships from a static diagram alone. I want to know: how are they born, can they exist alone, can they move, and how do they die?
Can the Child Change Parents?
Section titled “Can the Child Change Parents?”By default, a master-detail child can’t be moved to another parent. You can allow it, by selecting Allow reparenting on the relationship (Considerations for Object Relationships (opens in a new tab)). My instinct is conservative: if the business says the child belongs to one parent for life, I don’t make moving it easy. An item moving from one delivery to another should be a deliberate business event, not a field edit. Again, the setting isn’t the architecture. The lifecycle rule is, and the setting implements it.
Two more things that catch teams later. You can’t create a master-detail relationship on an object that already has data; you create a lookup, fill it on every record, then convert it. And you can only convert back to a lookup if there are no roll-up summary fields on the master. Watch what converting does to security, too: turning a lookup into a master-detail sets the child’s sharing to Controlled by Parent, and turning a master-detail back into a lookup sets the child’s organization-wide default to Public Read/Write (Considerations for Object Relationships (opens in a new tab)). Records that were private yesterday are open today, until someone notices. Choose early.
Roll-Ups Are Useful, but They Aren’t Free
Section titled “Roll-Ups Are Useful, but They Aren’t Free”I like roll-ups. Count the items on a delivery, sum the line amounts on an invoice, find the latest date: native, no code. The master-detail field goes on the child, but the roll-up goes on the parent. They come with fine print, though (Roll-Up Summary Field (opens in a new tab)):
- Calculating roll-up values after certain changes (a new roll-up field, a changed formula it depends on, a forced recalculation) can take up to 30 minutes, depending on how many records are affected. I’ve watched people wonder why the number on the parent hasn’t changed yet.
- They can’t summarize everything. An auto number can’t be the field you aggregate. And a roll-up can summarize a formula field only if that formula doesn’t reach across to another object and doesn’t use a function that changes on its own, such as
NOW()orTODAY(). A “days overdue” formula built onTODAY()changes every night without anyone saving a record, so there’s nothing for the roll-up to recalculate from. That kind of number needs a scheduled flow, or a report. - The filter has limits too: no long text area, multi-select picklist, Description, system fields like Last Activity, cross-object formulas or lookup fields.
- Roll-ups aren’t on edit pages, so a validation rule can use one but can’t show its error there.
And don’t reverse the decision. Don’t say, “We need a roll-up, so this must be master-detail.” Say, “This child truly belongs to this parent, the ownership and lifecycle fit, and one of the benefits is native roll-ups.” If the semantics don’t fit, solve the calculation another way. Don’t distort the data model to get a feature.
So what’s the other way? You build the roll-up yourself: a field on the parent that holds the calculated value, and automation that keeps it current. Say Retail Partner is a lookup from Delivery, as it should be, and the business wants Open Deliveries on the partner. Add a number field, Open Deliveries, to the partner. Then a record-triggered flow, or an Apex trigger when the volume or the logic calls for code, recalculates it whenever a delivery changes. It works over a lookup, it can filter on anything, and it can use dates and formulas a native roll-up can’t.
But now it’s yours to get right, and that’s where these go wrong. The automation has to fire on every change that matters: a new child, an edited child, a deleted child, an undeleted child, and a child moved to another parent, which means recalculating both the old parent and the new one. It has to handle a data load of 200 records at a time without hitting limits. Recount rather than add and subtract, so one missed event doesn’t leave the number wrong forever. Plan a way to recalculate everything, for the first load and the day it drifts. And remember every child save now updates the parent, so a parent with thousands of children brings back the locking we’ll see in a moment. A native roll-up does all of that for you; a custom one is a small piece of software you own.
Three Levels Deep: Stacking Master-Details
Section titled “Three Levels Deep: Stacking Master-Details”The platform has a shape, and master-detail has two dimensions of it. The first is depth.
You can stack master-details three custom detail levels deep, and that’s the bottom (Considerations for Object Relationships (opens in a new tab)). In class I draw it as an account with an order (one), the order with its items (two), and the items with their details (three), and then I try to add a fourth and Salesforce won’t let me. On Steve Trucking it might look like this: a Delivery is the master; its Delivery Items are the first level; an item’s Install Tasks are the second; and each task’s Task Steps are the third. A fourth level, say a Step Note, has to be a lookup.
A few rules come with the stack:
- Standard objects can’t be on the detail side of a custom object. A custom object can be a detail of Account; Account can’t be a detail of yours.
- An object can appear only once in a multilevel stack. Salesforce doesn’t want you looping back on yourself: a subdetail can’t also be the master of its own master.
- The master can’t roll up the bottom level directly. If Delivery wants the number of Task Steps, Install Task rolls up its steps, Delivery Item rolls up those roll-ups, and Delivery rolls up the items: one level at a time.
- Ownership and sharing come from the top. Every level inherits the owner and the access of the master.
- Deleting the master deletes everything beneath it, and undeleting it brings everything back.
Three levels is usually plenty. If your design keeps wanting a fourth, ask whether every level really belongs to the one above it for life. And remember you get to choose which link breaks the chain. The fourth level doesn’t have to be the lookup: maybe an Install Task doesn’t truly belong to its Delivery Item, it’s scheduled and assigned on its own, so that link becomes a lookup, and now Install Task starts a new chain with Task Step and Step Note beneath it. Pick the link where the child really has its own life, and make that one the lookup.
Now Install Task has its own owner and its own sharing, a delivery can be deleted without taking its install tasks with it, and Install Task can have two more levels beneath it. That’s the trade: the chain is shorter, and the install task’s life is its own.
Two Parents Wide: the Salesforce Junction Object
Section titled “Two Parents Wide: the Salesforce Junction Object”First, a word about words, because “junction object” means two things, and I teach both.
In chapter 2 we found the logical junction object: the junction of two key ideas that becomes a thing of its own, with its own attributes. A dog knows many tricks, a trick is known by many dogs, and Dog Trick sits between them holding the skill level and the date. That’s a logical junction object, in the logical model, long before anyone decides lookup or master-detail.
Salesforce uses the term more narrowly. When Salesforce says junction object, it means a custom object with two master-detail relationships (Create a Many-to-Many Object Relationship (opens in a new tab)). I’ll call that a Salesforce Junction Object. Every Salesforce Junction Object is a logical junction object, but not every logical junction object becomes a Salesforce Junction Object: build one with a master-detail and a lookup, or two lookups, and it’s still a logical junction object, just not the Salesforce kind. (Salesforce isn’t perfectly consistent itself: its own object reference calls some standard objects built on lookups “junction objects”. On the exam, assume the narrow definition.)
Test knowledge. A Salesforce Junction Object is a custom object with two master-detail relationships, and that’s what Salesforce means when it says “junction object”. The logical junction object is the wider modeling idea: any object that joins two others in a many-to-many and carries its own attributes, however it’s built.
The second dimension is width. Can a child have two master-detail parents? Yes. Three? No. Each custom object can have up to two master-detail relationships (Considerations for Object Relationships (opens in a new tab)). Two master-detail parents is how you build a Salesforce Junction Object for a many-to-many. Crew and Truck meet in a Crew Assignment, and as we found in chapter 2, it isn’t plumbing: it has a date, a route, maybe a status. The junction is where the relationship becomes a business concept. Salesforce’s tips for building one: give it a name that says what it is, make its record name an auto number, and rename each master’s related list to the other master, so the Crew page shows “Trucks” and the Truck page shows “Crews” (Create a Many-to-Many Object Relationship (opens in a new tab)).
Here’s the intricacy. One of the two parents is the primary, and it’s the one whose master-detail field you created first. There’s no visual indication of which one that is, so it’s a classic test question, and a classic surprise.
What does the primary decide? Three things (Create a Many-to-Many Object Relationship (opens in a new tab)):
- Look and feel. The junction’s pages use the primary master’s color and icon.
- Owner. The junction records inherit the owner of the primary master record. You never see it, because a detail has no Owner field; it only matters if you later remove both master-detail relationships.
- Division, if your org uses divisions, the same way.
And the other one is the secondary. What does it mean?
- It’s in line to become primary. Delete the primary master-detail field or convert it to a lookup, and the secondary becomes the primary.
- It sets the scope of the reports. Salesforce gives you two report types: “Primary master with junction object and secondary master” and “Secondary master with junction object and primary master”. The master listed first decides which records the report can show.
- It counts just as much for access. Here’s how I put it: ownership from the primary, access from both, and the most restrictive wins. A junction, like any detail, has no share table of its own. Salesforce checks the user’s access to both master records, through the Sharing Setting on each master-detail field. If both are set to Read/Write, the user needs Read/Write on the crew and on the truck to edit the Crew Assignment (Considerations for Object Relationships (opens in a new tab)).
- It deletes just as much. Delete either master, the crew or the truck, and its junction records go to the Recycle Bin. Delete both and they’re gone for good.
A few more rules: both masters can have roll-up summaries from the junction, and the junction’s formulas and validation rules can reach fields on both. But a junction can’t be the master of anything else, so it can’t sit in the middle of a stack, and the two masters can’t be the same object; a many-to-many from an object to itself needs a different design. And if a parent has more than 200 junction records and the junction rolls up to the other parent, Salesforce won’t let you delete that parent until you’ve removed enough of them.
So: which parent should be primary? Create the one that owns the meaning first. For a Crew Assignment, the crew is doing the work, so I’d create Crew first. And then write it down, because nothing on the screen will tell the next person.
Having said all that, I don’t end up with many Salesforce Junction Objects. Typically an object has one master-detail parent, and it’s the same kind of data: customer data under customer data, transactional under transactional (remember chapter 2’s kinds of data: customer, transactional, reference). When its other parent is a different kind, usually a reference object, that relationship is a lookup. A Delivery Item belongs to its Delivery: master-detail, both transactional. It points to the Product it carries with a lookup, because a product is reference data with a life of its own, and nobody wants deleting a product to take years of delivery history with it. Delivery Item is still a logical junction object between a delivery and the products on it; it just isn’t a Salesforce Junction Object.
Self-Relationships: When the Line Comes Back
Section titled “Self-Relationships: When the Line Comes Back”An object can relate to itself: a parent account, a manager, a distribution center that reports to a regional hub. Salesforce builds in two you’ll meet in almost every org: Account to Account, the Parent Account field that builds the account hierarchy, and Case to Case, the Parent Case from module 2 that groups related cases. A self-relationship has to be a lookup, and a record can’t point to itself, although two records can point at each other (Considerations for Object Relationships (opens in a new tab)). On the User object it’s a special type of its own, the hierarchical relationship, used for things like a user’s manager. The mechanics are easy; the naming matters. A lookup from Distribution Center to Distribution Center called Distribution_Center__c helps nobody. Parent? Backup? Overflow? Name the relationship for the role, not for the object it points to.
Hierarchical: the User Object’s Own Relationship
Section titled “Hierarchical: the User Object’s Own Relationship”This one is small, and it’s exactly the kind of little-known, one-of-a-kind fact I’d expect an exam to draw on. Hierarchical is a special lookup that exists only on the User object. It links one user to another user, and Salesforce won’t let the chain loop back: a user can’t point to themselves, directly or indirectly (Object Relationships Overview (opens in a new tab)). If Maria’s manager is Dev, Dev’s manager can’t be Maria, or anyone who reports up to Maria.
That’s the difference from the self-relationships above. On Account or a custom object, two records can point at each other. On User, the hierarchy has to stay a hierarchy. And it’s the only way to relate User to User: an ordinary lookup from User to itself isn’t offered.
You already have one. The standard Manager field on User is a hierarchical relationship, and approvals can use it: send this request to the submitter’s manager. You can create your own too, say an Escalation Contact or a Backup Approver, and an approval can route along it the same way (ApprovalProcess, Metadata API (opens in a new tab)). Don’t confuse it with the role hierarchy, which drives record access. A hierarchical field is just a relationship between users; it doesn’t share a single record.
Test knowledge. The hierarchical relationship exists only on the User object, like the standard Manager field, and a user can’t point to themselves, directly or indirectly. It isn’t the role hierarchy.
Relationships Have Limits Too
Section titled “Relationships Have Limits Too”Each object can have two master-detail relationships at most. Lookup and master-detail fields together count as relationship fields: 40 per object by default, 50 at most on request. Roll-up summary fields: 25 per object by default, 40 at most (Increase the Maximum Relationships Allowed per Object (opens in a new tab); Increase the Maximum Limit of Roll-Up Summary Fields (opens in a new tab)). Salesforce adds that raising either limit can affect performance.
You don’t need to design to those numbers; you need to notice when you’re near them. An object with relationship after relationship hanging off it is telling you something. Maybe it genuinely is that central. Or maybe the model is wrong. (And chapter 18’s headroom rule applies: stay well under a limit, measured against year three.)
The 10,000-Child Question
Section titled “The 10,000-Child Question”Then there’s the parent with too many children. Salesforce’s own guidance is not to exceed about 10,000 child records for one master-detail parent (Considerations for Object Relationships (opens in a new tab)), and its guide to record access at scale says the same for parent-child relationships generally (Parent-Child Data Skew (opens in a new tab)). Record 10,001 doesn’t break the org. But past that point, saving a child can lock the parent, and sharing changes on the parent ripple through every child.
So when I see one parent, enormous numbers of children, I ask: why are they all under the same parent, who owns them, how are they queried, and what automation touches the parent? Every delivery under a single “Steve Trucking” account would pass 10,000 in a few days. An innocent one-to-many becomes a skew problem. The next module previews skew, and Part 2 goes deep.
Don’t Design the Line by Feature
Section titled “Don’t Design the Line by Feature”This is the habit I want from this module. Don’t start from “I need a roll-up,” “I need it required,” “I want inherited sharing.” Those are implementation clues. Start from the business: does the child have its own life, who owns it, can it exist alone, can it move, what happens when the parent goes, does the relationship carry data, and how big can each side get? Then choose the relationship that implements the answers.
Beyond the exam: what AI changes. AI can propose relationships in seconds. It can’t tell you whether the business will ever delete the parent. Faster diagramming doesn’t make a wrong relationship cheaper to reverse once millions of records and dozens of automations depend on it.
What an Architect Decides Here
Section titled “What an Architect Decides Here”- Whether the child has its own lifecycle or truly belongs to the parent, and whether ownership and access should be its own or inherited.
- Whether the child can exist without a parent, move between parents, or survive the parent’s deletion.
- What each lookup does when its parent is deleted: clear, block, or cascade.
- Whether a many-to-many is plumbing or a business concept, whether the logical junction object becomes a Salesforce Junction Object, which parent is primary, and what both parents mean for access.
- Whether the model fits the platform’s shape: three custom detail levels deep, two master-detail parents wide, the relationship and roll-up limits.
- Whether the expected number and distribution of children creates a skew risk that should change the design.
A relationship is a set of promises about how two pieces of data behave together. Make them deliberately.
Explore
Section titled “Explore”- Salesforce Help, Considerations for Object Relationships (opens in a new tab), checked 2026-10-13.
- Salesforce Help, Object Relationships Overview (opens in a new tab) and Create a Many-to-Many Object Relationship (opens in a new tab), checked 2026-10-13.
- Salesforce Help, Roll-Up Summary Field (opens in a new tab), checked 2026-10-13.
- Salesforce Developers, Metadata API, ApprovalProcess (opens in a new tab), checked 2026-10-13.
- Salesforce Help, Lookup Filters (opens in a new tab), checked 2026-10-13.
- Salesforce Help, Increase the Maximum Relationships Allowed per Object (opens in a new tab) and Increase the Maximum Limit of Roll-Up Summary Fields (opens in a new tab), checked 2026-10-02.
- Salesforce Developers, Designing Record Access for Enterprise Scale, Parent-Child Data Skew (opens in a new tab), checked 2026-10-02.
