Master-Detail vs Lookup
💬 In plain
words: Master-Detail is a
parent-child bond: child dies with the parent, inherits its sharing, and
enables roll-up summaries. Lookup is a loose reference: both records live
independently. Choose MD when the child has no meaning alone; choose lookup
when it does.
📌 Example: Invoice Line without an Invoice is meaningless
→ Master-Detail: delete the invoice, lines go too, and 'Invoice Total' is a
free roll-up. Contact to 'Preferred Hotel' → Lookup: hotel deleted, contact
lives on.
🎬 Real-Life
Example: The Roll-Up That Cost a Sprint Every Route__c screen
must show how many Delivery__c records it carries. Simple total. Live at all
times.
The Old/Bad Way: The team built Route–Delivery as a Lookup.
Lookups have no roll-up summary fields. So they wrote a trigger: count children
on insert, subtract on delete, recount on reparent, handle undelete, handle
bulk loads.
Why this is bad: You are rebuilding, by hand, a feature the
platform gives away free. Every missed edge case leaves a wrong total on a
manager's screen. And wrong totals destroy trust fast.
The New/Good Way: 1. Ask the real question first: is a Delivery
meaningless without its Route? Yes. Should deleting a Route delete its
Deliveries? Yes. 2. Then Master-Detail
is the honest answer. 3. Add a Roll-Up
Summary field: COUNT of Deliveries. The platform keeps it correct through
delete, undelete, and reparent.
The payoff: Pick the relationship for the behavior you need
— ownership, cascade delete, roll-ups — not for the line on the diagram.
Concept
Master-Detail (MD) makes the child depend on the parent. The child inherits the parent's owner and sharing. Delete the parent and the child goes with it. And you get Roll-Up Summary fields on the master: COUNT, SUM, MIN, MAX. A Lookup is a loose reference. The child keeps its own ownership and sharing. The field can be optional. There is no cascade delete — you only get 'delete this record also' through lookup filter behaviors. And there are no native roll-ups. This one choice drives your sharing design in Module 3, your roll-up strategy, and your delete behavior. It is structural, and it is hard to reverse later.
🧠Pick MD when:
child is dependent, shares parent's security, needs roll-ups. Pick Lookup when:
independent life, own sharing, optional link.
🧠360 Card —
Master-Detail vs Lookup
Rule: Master-Detail when the child cannot exist
alone. Lookup when it can.
Gain: cascade delete, roll-up summary fields,
inherited owner and sharing, required parent. Four things, free.
Price: coupling. The child gives up its own owner, its
own sharing, and its own life.
Limits: two Master-Details per child. Reparenting is
off by default. Twenty-five roll-up summary fields per parent. Forty lookups
per object.
Mirror — Lookup: optional link, own owner, own sharing, no
native roll-ups, no cascade delete.
Later: junction objects need both Master-Detail slots.
Spend one here and many-to-many is gone (2.2).
At volume: every child save locks the parent. Ten thousand
children under one parent is skew, and saves start queueing (10.6).
Core Q&A
Q: How do you decide between
Master-Detail and Lookup for a new relationship?
🎯
Say this first: Master-Detail if the child can't exist
alone and should inherit parent sharing (and you want roll-ups); Lookup for
everything looser.
A: Ask
three questions. One: does the child mean anything without the parent? If not,
use Master-Detail. Two: should the child's visibility follow the
parent's? Master-Detail inherits sharing, so if the child needs its own OWD
and its own sharing rules, use a Lookup. Three: do you need declarative
roll-ups? Native Roll-Up Summaries need Master-Detail. With a Lookup you fall
back to Flow, Apex, or a DLRS-style rollup. Then weigh the limits. An object
can have at most 2 Master-Detail relationships, and the child of one MD cannot
be the master of another MD chain beyond a limited depth.
Follow-ups (scenario-based)
Q1: You need to convert an
existing Lookup to Master-Detail on an object with 2M records. What are the
preconditions and the risks?
A1: Two
things must be true before you convert. Every child record needs a non-null
parent — no orphans. And you must accept that ownership on the child is
discarded. Children take the parent's owner and sharing from then on, so any
owner-based report, sharing rules, or assignment logic on the child
breaks. At 2M records the sharing recalculation is heavy. Plan it like a
migration: off-hours, with deferred sharing. Also check the roll-up limits on
the parent before you promise roll-ups as the payoff. The cap is 25 roll-up
summary fields, and the default is lower.
Q2: A child object needs
roll-ups on the parent, but also needs independent sharing. What are your
options?
A2: Keep
the Lookup, so the child keeps its own sharing. Then compute the roll-up some
other way. A record-triggered after-save Flow handles simple
counts. Apex in the trigger handler handles anything that needs aggregate
queries at volume. A scheduled batch recalculation handles very hot objects,
where an eventually-consistent total is good enough. Say the trade-off out
loud: real-time roll-ups in a trigger cost SOQL and DML on every
save, while batch roll-ups cost freshness. Common mistake: switching to
Master-Detail just to get roll-ups, and breaking the security model to do it.