---
name: salesforce-data-model
slug: salesforce-data-model
description: This skill should be used when the user asks to "set up Salesforce data model", "design Salesforce objects", "structure data in Salesforce", "model leads accounts contacts opportunities in Salesforce", "set up Salesforce for B2B SaaS", "design Salesforce architecture", "plan Salesforce object relationships", "set up custom objects in Salesforce", "model our CRM in Salesforce", or any variation of designing the data model, object architecture, and relationships in Salesforce CRM for B2B SaaS.
category: general
---

# Salesforce Data Model

Salesforce's data model is built on standard objects (Leads, Accounts, Contacts, Opportunities), their relationships, and custom objects you add. The Salesforce model is more complex than HubSpot's because Salesforce separates Leads from Contacts (the lead conversion model) and supports deeper customization. Getting the object architecture right prevents the most expensive Salesforce mistakes: broken reporting, orphan records, and data migrations that take months.

The principle: Salesforce is infinitely customizable. That's the risk, not the benefit. Every custom object, field, and automation adds maintenance debt. Build the simplest model that supports your sales motion and resist the urge to over-engineer.

## The Core Objects

### Lead

A Lead is an unqualified person who hasn't been associated with an Account or Opportunity yet. Leads live in their own table, separate from Contacts.

| Field category | Key fields | Purpose |
|---------------|-----------|---------|
| Identity | Email, Name, Company, Title, Phone | Identification and dedup |
| Source | Lead Source, Campaign Member, UTM fields (custom) | Attribution |
| Qualification | Lead Status, Lead Score (custom), ICP Tier (custom) | Routing and prioritization |
| Ownership | Lead Owner | Assignment and accountability |

**The Lead vs Contact decision:**

This is the most debated topic in Salesforce architecture. Salesforce's default model: new people start as Leads. When qualified, they "convert" to a Contact + Account + (optionally) Opportunity.

| Approach | How it works | Best for | Trade-offs |
|----------|-------------|----------|-----------|
| Classic Lead model | New people → Lead. Qualified → Convert to Contact/Account/Opp | High-volume inbound with SDR qualification layer | Two objects to manage. Reporting across Lead + Contact is painful |
| Contact-only model | Skip Leads entirely. Create Contacts + Accounts immediately | Low-volume, high-ACV. ABM-first motions | Loses the qualification "gate." Contacts clutter the Account view |
| Hybrid | Use Leads for inbound/unknown. Create Contacts directly for outbound/ABM targets | Most B2B SaaS at scale | More complex but matches reality |

**Lead rules:**
- If your SDR team qualifies inbound before passing to AEs, use the Lead object. The Lead → Contact conversion is the qualification handoff
- If you're ABM-first and your team researches accounts before outreach, create Contacts directly on the target Account. No Lead needed
- Never let Leads accumulate unconverted. Leads older than 90 days with no activity should be either converted (if qualified) or archived. Stale Leads are invisible to Account-based reporting
- Dedup Leads against existing Contacts before creation. A new Lead for someone who's already a Contact on a customer Account creates confusion

### Account

An Account is a company. One record per business entity. Accounts are the center of the Salesforce data model. Everything rolls up to Accounts.

| Field category | Key fields | Purpose |
|---------------|-----------|---------|
| Identity | Account Name, Website/Domain, Account Number | Identification and dedup |
| Firmographics | Industry, Employee Count, Annual Revenue, Billing Address | ICP scoring, segmentation |
| Classification | Account Type (Prospect, Customer, Partner, Competitor), ICP Tier (custom), ABM Tier (custom) | Segmentation and prioritization |
| Ownership | Account Owner | Territory assignment, accountability |
| Hierarchy | Parent Account | Enterprise hierarchy modeling |

**Account rules:**
- Use Website/Domain as the dedup key, not Account Name. "Acme" vs "Acme Inc" creates duplicates. Domains are unique
- Set Account Type as required. Prospect, Customer, Partner, Competitor, Vendor. Without this, Account lists are a mix of everything
- Use Parent Account for enterprise hierarchies. Acme Corp (parent) → Acme EMEA (child) → Acme UK (child of EMEA). This enables rollup reporting across the org
- Every Contact and every Opportunity must belong to an Account. Orphan Contacts and orphan Opps break every report that matters

### Contact

A Contact is a person associated with an Account. After Lead conversion, the person becomes a Contact linked to their Account.

| Field category | Key fields | Purpose |
|---------------|-----------|---------|
| Identity | Email, Name, Title, Phone, Mailing Address | Communication and identification |
| Role | Title, Department, Seniority Level (custom), Persona (custom) | Persona-based routing and messaging |
| Relationship | Account (lookup), Reports To (hierarchy), Contact Role on Opportunity | Org chart and buying committee |
| Engagement | Last Activity Date, Lead Source (carried from Lead), Campaign History | Activity tracking, attribution |

**Contact rules:**
- Every Contact must be on an Account. Salesforce allows orphan Contacts (no Account). Don't allow it. Enforce via validation rule
- Use Contact Roles on Opportunities to track the buying committee. "Decision Maker," "Influencer," "Technical Evaluator," "Champion." This is Salesforce's native buying committee tracking
- Carry Lead Source from the Lead record during conversion. If you lose Lead Source at conversion, attribution is broken permanently for that record
- Title standardization matters more in Salesforce than HubSpot because Salesforce has no native scoring. Build a "Seniority Level" custom field (IC, Manager, Director, VP, C-Level) derived from Title via automation

### Opportunity

An Opportunity is a deal. One record per potential transaction. Opportunities are the pipeline and forecasting object.

| Field category | Key fields | Purpose |
|---------------|-----------|---------|
| Identity | Opportunity Name, Owner | Tracking, accountability |
| Value | Amount, ARR (custom), Expected Revenue (Amount × Probability) | Pipeline and forecasting |
| Stage | Stage, Probability (auto-set by stage), Forecast Category | Sales process, forecasting |
| Timeline | Close Date, Created Date, Days in Stage (custom formula) | Velocity, forecast accuracy |
| Associations | Account (required), Contact Roles, Primary Contact (custom) | Buying committee, account attribution |
| Source | Lead Source (custom, carried from Contact), Opportunity Source (custom) | Pipeline attribution |
| Qualification | MEDDPICC fields (custom), Next Step, Competitor (custom) | Deal health tracking |

**Opportunity rules:**
- Naming convention: "[Account Name] - [Product] - [ARR]". Enforce with a formula field or automation. "Opp-47" is useless in a pipeline view
- Every Opportunity must have an Account. Salesforce enforces this natively
- Every Opportunity must have at least one Contact Role. Salesforce does NOT enforce this natively. Add a validation rule or workflow that requires at least one Contact Role before stage advancement
- Use Opportunity Record Types for different sales motions: New Business, Expansion, Renewal, Partner. Each gets its own stage path and page layout
- Stage probability should map to your actual historical close rates, not Salesforce defaults. Calibrate quarterly

---

## Opportunity Stages

Design stages to match your sales process with clear, observable exit criteria.

### Recommended B2B SaaS stages

| Stage | Probability | Exit criteria | Required fields |
|-------|-------------|--------------|----------------|
| Prospecting | 10% | Initial outreach sent, meeting requested | Contact Role assigned |
| Discovery | 20% | Discovery call completed, need confirmed | Next Step, Close Date |
| Evaluation | 40% | Demo delivered, technical validation in progress | Champion identified (custom checkbox) |
| Proposal | 60% | Proposal sent, pricing reviewed | Amount, Proposal Date (custom) |
| Negotiation | 75% | Terms under review, legal/procurement engaged | Contract sent, Decision criteria documented |
| Verbal Commit | 90% | Verbal yes, awaiting signature | Expected sign date |
| Closed Won | 100% | Contract signed, payment terms set | All fields complete |
| Closed Lost | 0% | Deal lost | Loss Reason (required), Competitor (required if lost to competitor) |

**Stage rules:**
- 6-8 stages max. Every stage added slows down rep data entry and dilutes conversion metrics
- Each stage must have observable exit criteria. "The prospect is interested" is not observable. "Discovery call completed, need confirmed in call notes" is observable
- Require fields at stage progression using validation rules. Don't let a deal advance to Proposal without an Amount. Don't let it close without a Loss Reason
- Calibrate probability quarterly using actual historical data. If deals in "Evaluation" close at 35% (not the default 40%), update it

### Multiple pipelines via Record Types

| Record Type | Use for | Stages | Why separate |
|------------|---------|--------|-------------|
| New Business | First-time customer deals | Full 8-stage process | Longest cycle, most stages |
| Expansion | Upsell/cross-sell to existing customers | Discovery → Proposal → Negotiation → Closed | Shorter cycle, skip early stages |
| Renewal | Contract renewals | Renewal Pending → Negotiation → Closed | Different process, different metrics |
| Partner | Partner-sourced deals | Partner Qualified → Evaluation → Proposal → Closed | Different source, different tracking |

---

## Relationships and Lookups

### Standard relationships

```
Lead (standalone, pre-conversion)
  ↓ (converts to)
Contact → Account (required lookup)
Contact → Opportunity (via Contact Role junction)
Opportunity → Account (required lookup)
Account → Account (Parent Account self-lookup, for hierarchy)
Campaign → Contact/Lead (via Campaign Member junction)
```

### Key relationship rules

- **Contact to Account is required.** Enforce with validation rule if needed. Orphan Contacts are invisible to Account-level reporting
- **Contact to Opportunity is many-to-many** via Contact Roles. Use it. Don't create a custom "Primary Contact" lookup on Opportunity as a replacement. Contact Roles tracks the full committee
- **Account hierarchy** (Parent Account) is essential for enterprise. Without it, you can't roll up pipeline across business units of the same parent company
- **Campaign Members** link Contacts and Leads to Campaigns for attribution. Use Campaign Influence (multi-touch) for pipeline attribution, not just "Primary Campaign Source" (first-touch)

### Custom lookups to add

| Lookup | From | To | Purpose |
|--------|------|-----|---------|
| SDR (custom) | Opportunity | User | Track which SDR sourced the deal (separate from Opp Owner/AE) |
| Partner Account (custom) | Opportunity | Account | Track partner-sourced deals linked to the partner's Account |
| Previous Vendor (custom) | Account | Text/Picklist | Track what tool/vendor the customer used before you |
| Referral Contact (custom) | Opportunity | Contact | Track who referred the deal |

---

## Custom Fields Strategy

### Naming conventions

| Convention | Rule | Example |
|-----------|------|---------|
| Prefix custom fields | Start with category | `ICP_Tier__c`, `ABM_Status__c`, `Outbound_Last_Touch__c` |
| Suffix with type hint | Add type when ambiguous | `MQL_Date__c`, `Champion_Identified__c` (checkbox) |
| Use underscores | Consistent separator | `Lead_Source_Detail__c` not `LeadSourceDetail__c` |
| API name matches label | Keep aligned | Label: "ICP Tier" → API: `ICP_Tier__c` |

### Essential custom fields for B2B SaaS

**On Lead:**

| Field | Type | Purpose |
|-------|------|---------|
| `ICP_Tier__c` | Picklist (1, 2, 3, Not ICP) | Pre-qualification scoring |
| `Lead_Score__c` | Number | Scoring (if not using Pardot/MCAE) |
| `Lead_Source_Detail__c` | Picklist | Detailed source beyond standard Lead Source |
| `Seniority_Level__c` | Picklist (IC, Manager, Director, VP, C-Level) | Persona routing |
| `Persona__c` | Picklist | ICP persona category |

**On Account:**

| Field | Type | Purpose |
|-------|------|---------|
| `ICP_Tier__c` | Picklist | Account prioritization |
| `Target_Account__c` | Checkbox | ABM flag |
| `ABM_Tier__c` | Picklist (1:1, 1:Few, 1:Many) | ABM motion assignment |
| `Tech_Stack__c` | Multi-select picklist | Stack-based targeting |
| `Funding_Stage__c` | Picklist | Firmographic segmentation |
| `Account_Lifecycle__c` | Picklist | Account-level journey stage |
| `Health_Score__c` | Number | Customer health (post-sale) |

**On Opportunity:**

| Field | Type | Purpose |
|-------|------|---------|
| `Opp_Source__c` | Picklist (Inbound, Outbound, ABM, Referral, Partner, Expansion) | Pipeline source attribution |
| `ARR__c` | Currency | Recurring revenue value (Amount may include one-time fees) |
| `Champion_Identified__c` | Checkbox | Deal health signal |
| `Multi_Threaded__c` | Checkbox | Deal risk signal |
| `Competitor__c` | Multi-select picklist | Competitive tracking |
| `Loss_Reason__c` | Picklist | Win/loss analysis (required on Closed Lost) |
| `Days_in_Stage__c` | Formula (TODAY() - Last Stage Change Date) | Velocity tracking |
| `MEDDPICC_Score__c` | Number (rollup of sub-fields) | Enterprise deal qualification |
| `SDR__c` | Lookup to User | Source attribution to SDR |
| `Next_Step__c` | Text | Deal progression tracking |

**On Contact:**

| Field | Type | Purpose |
|-------|------|---------|
| `Seniority_Level__c` | Picklist | Persona-based routing |
| `Persona__c` | Picklist | ICP persona |
| `Outbound_Status__c` | Picklist | Sequence tracking |
| `MQL_Date__c` | Date | Velocity measurement |
| `SQL_Date__c` | Date | Velocity measurement |

---

## Lead Conversion Mapping

When a Lead converts, Salesforce creates a Contact and (optionally) an Account and Opportunity. Field mapping determines which Lead fields transfer to which Contact/Account/Opportunity fields.

### Critical mappings

| Lead field | Maps to | Object | Notes |
|-----------|---------|--------|-------|
| Email | Email | Contact | Auto-mapped |
| Name | Name | Contact | Auto-mapped |
| Company | Account Name | Account | Auto-mapped |
| Title | Title | Contact | Auto-mapped |
| Lead Source | Lead Source | Contact (and Opp if created) | MUST be mapped or attribution is lost |
| Lead Score | (custom) | Contact | Custom mapping required |
| ICP Tier | ICP Tier | Account | Custom mapping required |
| Persona | Persona | Contact | Custom mapping required |
| Seniority Level | Seniority Level | Contact | Custom mapping required |
| Lead Source Detail | Lead Source Detail | Contact + Opportunity | Custom mapping required |

**Conversion rules:**
- Map every custom Lead field to its Contact/Account equivalent. Unmapped fields are lost permanently at conversion
- Test conversion with a sample Lead before going live. Verify every field transfers correctly
- Set up duplicate matching rules. When converting a Lead, Salesforce should match to an existing Account (by domain) and existing Contact (by email) instead of creating duplicates
- Never allow Lead conversion without an Account. The default allows it. Disable it. Contacts without Accounts break everything

---

## Reporting Considerations

### Reports that break without proper data model

| Report | Requires | Common failure |
|--------|---------|----------------|
| Pipeline by source | `Opp_Source__c` on Opportunity | Using Lead Source (tracks person source, not deal source) |
| Buying committee coverage | Contact Roles on Opportunity | No Contact Roles assigned. Report shows no committee data |
| Account-level pipeline | Opportunity → Account relationship | Orphan Opps not linked to Accounts |
| Lead-to-close velocity | MQL Date, SQL Date, Opp Created Date, Close Date | No date stamp fields on Contact for MQL/SQL transitions |
| Multi-touch attribution | Campaign Influence | Using Primary Campaign Source only (first-touch, misses multi-touch) |
| Enterprise rollup | Parent Account hierarchy | No Parent Account relationships set |
| Win/loss analysis | Loss Reason, Competitor fields | Not required on Close Lost. Fields are empty |

---

## Data Model by Company Stage

### Pre-Series A (< 10 reps)

- Standard objects only: Leads, Accounts, Contacts, Opportunities
- 10-15 custom fields
- One Record Type (New Business)
- No custom objects
- Classic Lead model

### Series A-B (10-50 reps)

- All standard objects with 20-30 custom fields
- 2-3 Record Types (New Business, Expansion, Renewal)
- Contact Roles enforced
- Lead conversion mapping fully configured
- ICP and ABM fields on Account
- MEDDPICC or BANT fields on Opportunity

### Series C+ (50+ reps)

- Standard objects + 1-3 custom objects
- 30-50 custom fields with strict governance
- Multiple Record Types per object
- Parent Account hierarchies for enterprise
- Campaign Influence for multi-touch attribution
- Territory management enabled
- CPQ (Configure Price Quote) for complex pricing

---

## Anti-Pattern Check

- Leads never converted, accumulating for years. 50,000 unconverted Leads older than 12 months is a data graveyard. Convert qualified ones, archive the rest. Set a 90-day conversion or archive policy
- No Contact Roles on Opportunities. The buying committee is invisible. Pipeline reviews can't assess multi-threading. Require at least one Contact Role before advancing past Discovery
- Lead Source lost at conversion. The #1 attribution mistake in Salesforce. Map Lead Source from Lead to Contact AND Opportunity during conversion setup. Test it
- Custom fields with no naming convention. `Score`, `Score2`, `New_Score__c`, `Final_Score__c` proliferate. Prefix every field with a category. Delete unused fields quarterly
- Orphan Contacts (no Account). Salesforce allows it. Don't. Add a validation rule requiring Account on Contact creation. Orphans break every account-level report
- 15 Opportunity stages. Reps skip stages because there are too many. 6-8 stages max. Each must have observable exit criteria
- Amount field used for both one-time and recurring revenue. A $50K deal that's $10K ARR looks the same as a $50K ARR deal. Create a separate `ARR__c` field for recurring revenue
- No required fields on Closed Lost. Every lost deal should capture why. Without Loss Reason (required on stage change to Closed Lost), win/loss analysis is impossible
- Over-customized on Day 1. 5 custom objects, 80 custom fields, and 30 automation rules before the first deal closes. Start simple. Add complexity as the sales motion matures and data volume justifies it