One-to-One Relationships in Salesforce: How to Build Them

Blog / Salesforce · October 4, 2017 · Updated June 10, 2026 · 7 min read
One-to-One Relationships in Salesforce: How to Build Them

Salesforce does not provide a native one-to-one (1:1) relationship field type. Out of the box you only get one-to-many relationships (lookup and master-detail) and many-to-many (built with a junction object). To build a true one-to-one relationship, you create a lookup or master-detail field on the child object pointing to the parent, then enforce uniqueness — usually with a Unique text field storing the parent Id, populated by a Flow or Apex trigger — so the platform rejects any second child record.

That enforcement step is the part most tutorials skip. The relationship field alone gives you 1:many; the uniqueness constraint is what turns it into 1:1.

Key takeaways

  • No built-in 1:1. Salesforce relationship field types are lookup, master-detail, and (via junction) many-to-many only.
  • Pattern: put a lookup or master-detail on the child, then add a Unique text field that stores the parent's Id, set automatically by a before-save Flow or Apex trigger. Uniqueness on that field is what blocks a second child.
  • Master-detail gives cascade delete, inherited ownership/sharing, and roll-up summaries; lookup is independent and optional but supports neither cascade nor roll-ups by default.
  • Validation-rule / roll-up approach is an alternative: a roll-up count on the parent plus a validation rule that errors when the count would exceed 1.
  • True 1:1 always requires custom enforcement, because the declarative UI only offers 1:many.

What relationship types does Salesforce actually offer?

Understanding the native options makes it clear why 1:1 needs extra work. If you are new to these, our guide to creating a master-detail relationship in Salesforce covers the foundational type in depth, and you can visualise any relationship with Schema Builder in Salesforce.

Relationship Native cardinality Cascade delete Child ownership / sharing Roll-up summary Field optional?
Lookup One-to-many No (set to clear or restrict) Independent of parent No Yes (optional)
Master-detail One-to-many Yes (delete parent → deletes children) Inherited from parent Yes (on parent) No (required)
Many-to-many (junction object) Many-to-many Per master on the junction Per the two master-detail links Yes n/a
"One-to-one" (emulated) One-to-one Lookup: no / Master-detail: yes Depends on base field Depends on base field Depends on base field

The last row is not a real field type — it is a lookup or master-detail field with a uniqueness constraint bolted on.

How do you build a one-to-one relationship? (worked example)

Let's link Employee (parent) to Employee Profile (child), where each employee has exactly one profile and each profile belongs to exactly one employee.

Step 1 — Add the relationship field on the child

On the Employee Profile object, create a Lookup (or Master-Detail) field named Employee pointing to the Employee object. This establishes the link, but at this point Salesforce will happily let you attach many profiles to one employee.

Choose Master-Detail if the profile should be deleted when the employee is deleted, should inherit the employee's sharing, and you want roll-up summaries. Choose Lookup if the profile must exist independently or the link is optional.

Step 2 — Add a Unique text field to enforce the constraint

On Employee Profile, create a custom Text field named Employee Key, length 18, and tick Unique (and External ID if you also want upsert matching). This field will hold the parent record's Id. Because it is marked Unique, the database physically rejects a second profile that references the same employee.

Step 3 — Populate the Unique field automatically

The user fills in the lookup; you copy the related Id into Employee Key automatically so they never see it. A before-save Record-Triggered Flow is the lowest-code option:

  • Object: Employee Profile
  • Trigger: A record is created or updated
  • Condition: Employee__c is not null
  • Action: Update Triggering Record → set Employee_Key__c = {!$Record.Employee__c}

Now the first profile saves fine; a second profile pointing at the same employee fails on the unique index with a duplicate-value error. That single constraint is what makes the relationship one-to-one.

Can you enforce one-to-one with Apex instead?

Yes. A before-insert/before-update trigger can copy the Id into the unique field, letting the unique index do the rejection — or you can check explicitly and throw a friendly error.

trigger EmployeeProfileTrigger on Employee_Profile__c (before insert, before update) {
    for (Employee_Profile__c profile : Trigger.new) {
        // Mirror the parent Id into the Unique text field; the
        // unique index then guarantees at most one profile per employee.
        profile.Employee_Key__c = profile.Employee__c;
    }
}

If you prefer an explicit, user-friendly message rather than the raw duplicate-value error, query for an existing child before insert:

trigger EmployeeProfileGuard on Employee_Profile__c (before insert) {
    Set<Id> employeeIds = new Set<Id>();
    for (Employee_Profile__c p : Trigger.new) {
        if (p.Employee__c != null) employeeIds.add(p.Employee__c);
    }
    Map<Id, Employee_Profile__c> existing = new Map<Id, Employee_Profile__c>();
    for (Employee_Profile__c e : [SELECT Id, Employee__c FROM Employee_Profile__c WHERE Employee__c IN :employeeIds]) {
        existing.put(e.Employee__c, e);
    }
    for (Employee_Profile__c p : Trigger.new) {
        if (existing.containsKey(p.Employee__c)) {
            p.addError('This employee already has a profile. Only one profile is allowed per employee.');
        }
    }
}

Keep enforcement in a trigger or before-save flow — not just a validation rule — so it holds for API and bulk inserts too. Follow Salesforce customization best practices to keep the automation one-trigger-per-object and bulk-safe.

What about the roll-up summary + validation rule approach?

If you used a master-detail field in Step 1, you have a declarative alternative that needs no unique field:

  1. On the parent (Employee), create a Roll-Up Summary field Profile_Count__c of type COUNT over the child Employee Profiles.
  2. On the child (Employee Profile), add a validation rule that errors when the parent already has one child, e.g. Employee__r.Profile_Count__c >= 1 on insert.

This is fully clickable but only works with master-detail (roll-ups require it), and validation rules evaluate per record, so test bulk loads carefully. The Unique-field pattern is generally more robust and works with both lookup and master-detail.

Lookup vs master-detail: which base field for 1:1?

Pick based on lifecycle and sharing, then add uniqueness on top of either:

  • Use master-detail when the child cannot exist without the parent, should be deleted with it, should inherit the parent's owner and sharing, and you want roll-up summaries. The child becomes a detail and is always required.
  • Use lookup when the relationship is optional, the child has its own lifecycle and ownership, or you may need to reparent it freely. Remember lookups do not cascade-delete or roll up by default.

Because master-detail controls the child's sharing and visibility, double-check that downstream users have the access you expect — see how to set field-level security in Salesforce when locking down the relationship and key fields.

Frequently Asked Questions

Does Salesforce have a native one-to-one relationship field type?

No. Salesforce only provides lookup and master-detail (both one-to-many) and many-to-many via a junction object. A one-to-one relationship is always emulated by adding uniqueness enforcement on top of a lookup or master-detail field.

How do I make a Salesforce relationship one-to-one?

Create a lookup or master-detail field on the child object pointing to the parent, add a Unique text field on the child, and populate it with the parent's Id using a before-save Flow or Apex trigger. The unique index then rejects any second child for the same parent.

Should I use a lookup or a master-detail field for one-to-one?

Use master-detail when the child should be deleted with the parent, inherit its sharing, and support roll-up summaries. Use lookup when the relationship is optional, the child needs independent ownership, or it must be reparented. Add the uniqueness constraint to either.

Can I enforce one-to-one without Apex code?

Yes. A before-save Record-Triggered Flow can copy the parent Id into a Unique text field, which is enough to block duplicates. Alternatively, with master-detail you can use a roll-up summary COUNT plus a validation rule, with no code at all.

Why does a unique field create a one-to-one relationship?

The lookup or master-detail field allows many children per parent. Storing the parent's Id in a field marked Unique means the database will not accept two child records with the same parent Id, which caps each parent at exactly one child — a one-to-one relationship.

What is the difference between one-to-one and many-to-many in Salesforce?

One-to-one links each parent to at most one child and is emulated with uniqueness enforcement. Many-to-many lets many records on each side relate to many on the other and is built with a junction object that has two master-detail fields, one to each related object.


Need a relationship model, data architecture, or automation built and validated end to end? Our Salesforce consulting and development team has delivered 50+ projects since 2014, with 12+ years building on the platform.

Share this article