Skip to main content

SF-0035 · Scenario · Medium

How can we achieve one to one relationship?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026

Since Salesforce has no native 1:1 relationship field type, you implement one with two pieces working together: a relationship field (Lookup or Master-Detail on the child pointing to the parent), plus a uniqueness rule that prevents two child records from referencing the same parent. There are three common ways to enforce that uniqueness.

Step 1 — Pick the relationship type

  • Lookup: child owns its own lifecycle and sharing. Use when the two records have independent ownership or when the relationship is optional.
  • Master-Detail: child’s lifecycle and sharing follow the parent. Use when the child is conceptually part of the parent and 1:1 is a requirement.

Either way, this gives you the field that lets one child point to its parent. Now you need to stop a second child from pointing to the same parent.

Option A — Validation rule (admin-only, fastest)

On the child object, create a validation rule that fails if another record already references the same parent.

The cleanest way is to use a rollup-style approach via Process Builder/Flow or a helper field, or — more commonly — to use the Apex-free pattern: create a roll-up summary Child_Count__c on the parent (only works if the relationship is master-detail) and then on the child write a validation rule:

AND(
  NOT(ISBLANK(Parent__c)),
  Parent__r.Child_Count__c >= 1,
  OR(
    ISNEW(),
    ISCHANGED(Parent__c)
  )
)

This blocks creation of a second child for any parent that already has one. Works only with master-detail since lookup doesn’t allow roll-up summaries.

For lookup-based 1:1, you can use a helper formula on the parent populated by Flow or a trigger — but at that point Option B is cleaner.

Option B — Apex trigger (works for any relationship; scales for bulk)

A before insert, before update trigger on the child object:

trigger ChildOneToOne on Child__c (before insert, before update) {
    Set<Id> parentIds = new Set<Id>();
    for (Child__c c : Trigger.new) {
        if (c.Parent__c != null) parentIds.add(c.Parent__c);
    }
    if (parentIds.isEmpty()) return;

    // Find existing children for those parents
    Map<Id, Id> parentToExistingChild = new Map<Id, Id>();
    for (Child__c existing : [
        SELECT Id, Parent__c
        FROM Child__c
        WHERE Parent__c IN :parentIds
    ]) {
        parentToExistingChild.put(existing.Parent__c, existing.Id);
    }

    for (Child__c c : Trigger.new) {
        Id existingId = parentToExistingChild.get(c.Parent__c);
        if (existingId != null && existingId != c.Id) {
            c.addError('Each Parent can have only one Child__c.');
        }
    }
}

Key bulkification points: one SOQL for all parents in the batch, ignore matches where the existing child is the current record (so updates don’t false-flag).

Option C — Duplicate Management rule (declarative, scales)

Salesforce’s Duplicate Rules engine can enforce a matching rule on a lookup field. Setup:

  1. Create a Matching Rule on the child object matching on the lookup field (Parent__c).
  2. Create a Duplicate Rule that uses that matching rule, action = Block on Create/Edit.
  3. Activate both.

The user gets an in-line duplicate warning/block if they try to create a second child for the same parent. This works for both lookup and master-detail and requires no code, but counts against your duplicate-rule limits per object.

Option D — Make the lookup field Unique via a workaround

Salesforce won’t let you mark a Lookup or Master-Detail field as Unique directly. But you can create a Text formula field that just returns the lookup’s Id as text, and mark it Unique and as an External Id. This is a clever hack that works for small data volumes but has limitations:

  • Formula fields can’t be marked Unique in the field UI — but you can sometimes get the same effect via a text field populated by Flow

A cleaner version: add a Text(18) field Parent_Key__c marked Unique and External Id, then use a Flow (record-triggered) to copy the lookup Id into it on insert/update. The uniqueness constraint on the text field is enforced by the platform.

Which option to pick

OptionCodeBulk-safeWorks for LookupWorks for M-D
A — Validation rule + roll-upNoYesNo (roll-up needs M-D)Yes
B — TriggerYes (Apex)Yes (if written right)YesYes
C — Duplicate RuleNoYesYesYes
D — Unique text-field workaroundNo (Flow)YesYesYes

For modern admin-led implementations, Duplicate Rule (Option C) is the recommended default. It’s declarative, fast to ship, and the error UI is good.

End-to-end recipe (declarative)

  1. Create Child__c with a Lookup field Parent__c to Parent__c. Mark required.
  2. In Setup → Matching Rules, create rule on Child__c matching Parent__c exactly.
  3. In Setup → Duplicate Rules, create rule using that matching rule, action Block.
  4. Activate both. Test: try to create two Child__c rows for the same Parent__c — second one is blocked.

That’s a real 1:1 in Salesforce without writing any code.

Verified against: Salesforce Help — Duplicate Management and Apex Triggers. Last reviewed 2026-05-17.