Map Salesforce dependencies before you change fields, Flows or Apex

Use sf-intelligence to trace what depends on a Salesforce field, object, Flow, Apex class, layout, permission set, integration endpoint, or package boundary before you change it.

Last updated 2026-07-29

trace dependencies both ways in 2 minutes - no org, no auth

terminal
claude mcp add --transport stdio --scope user sf-intelligence-demo -- npx -y sf-intelligence demo

Then run the three worked examples below against real (synthetic) metadata: "what depends on Invoice__c.Amount__c?" for a field, "what does the Installation_On_Complete flow depend on, and what depends on it?" for a Flow traced both directions, and "what does PaymentService depend on, and what calls it?" for an Apex call graph with its blind spots named. Synthetic "Verdant Energy" org, served fully offline: no Salesforce login, no sf CLI. more on the demo →

Why Salesforce dependencies are hard to see

Salesforce dependencies live across XML metadata, Apex source, formulas, Flow definitions, Profile and Permission Set grants, page layouts, packages, and integration configuration. A single field can be referenced by automation, code, reports, validation rules, and external systems. sf-intelligence collects those signals into a local graph and reports how each dependency was found.

Dependency analysis targets

Change targetWhat to inspect
FieldFormulas, Flows, validation rules, Apex references, layouts, FLS, reports
ObjectChild relationships, automations, Apex queries, permissions, tabs, record types
FlowEntry criteria, called subflows, field writes, Apex actions, scheduled paths
Apex classCall graph, trigger entry points, tests, integrations, async jobs
Permission setObject and field grants, app access, tab access, assigned users through live reads
PackageNamespaced components, local references, uninstall and upgrade blast radius

Searches this page answers

  • "Salesforce dependency analysis for custom fields"
  • "Where is this Salesforce field used?"
  • "What depends on this Flow?"
  • "What breaks if I remove a picklist value?"
  • "What Apex classes call this method?"
  • "What is the impact of changing a permission set?"

Evidence-first output

The output is designed for review before a change lands. Each dependency points to a canonical component ID, the edge type, the confidence tier, and any known coverage caveat. If a metadata family was not retrieved, sf-intelligence says that the scan is partial instead of implying safety.

Three worked examples

Each example shows the question you type and the shape of the answer you get back. The output is a static picture of what the retrieved metadata references - not a runtime trace and not proof of what executes.

1. Before deleting a field

You are about to delete Account.Industry__c and want the upstream and downstream references first. This is the same trace behind where is a Salesforce field used, read here as a pre-change dependency check.

claude - sf-intelligence
 what depends on Account.Industry__c before I delete it?
▸ 5 components reference CustomField:Account.Industry__c
  ValidationRule:Account.Industry_Required   references   declared
  Flow:Lead_To_Account_Sync                  writesField  parsed
  ApexClass:AccountService (2 refs)          readsField   parsed
  Layout:Account-Sales Layout                references   declared
  Report:Accounts_by_Industry                references   declared
  provenance offline_snapshot
  coverageCaveat: layouts & reports fully modeled; dynamic Apex not parsed

Read this as a static shape: five families reference the field today. If a family comes back empty, that is no static evidence found for that family - not a verdict that the field is safe or unused. Weigh these dependents with the full delete simulation on Salesforce impact analysis.

2. Tracing a Flow both ways

You want to know what a record-triggered Flow reads and writes, and whether anything else invokes it before you deactivate it.

claude - sf-intelligence
 what does the Opportunity_Router flow depend on, and what depends on it?
▸ Flow:Opportunity_Router — record-triggered, after save on Opportunity
  depends on ↓
    CustomField:Opportunity.StageName   readsField    parsed
    CustomField:Account.Health__c       writesField   parsed
    ApexClass:NotifyCsm                  invokes       declared
  depended on by ↑
    no static evidence found — no retrieved component references this Flow
  provenance offline_snapshot · confidence: parsed

The empty upstream line is deliberate wording: the graph found no static evidence that another component calls this Flow, which is different from proving nothing does. A subflow invoked by a dynamically built name, or an invocation added since the last refresh, would not appear.

3. An Apex class call graph

You are refactoring an Apex class and need its resolved field access, its call graph, and - just as important - what the static parse could not see.

claude - sf-intelligence
 what does BillingService depend on, and what calls it?
▸ ApexClass:BillingService
  depends on ↓
    CustomField:Invoice__c.Amount__c    readsField    parsed
    CustomField:Invoice__c.Status__c    writesField   parsed
    ApexClass:TaxCalculator             calls         parsed
  depended on by ↑
    ApexTrigger:InvoiceTrigger          calls         parsed
    ApexClass:BillingServiceTest        calls         parsed
  blind spots on this class
    1 dynamic SOQL string not resolved — Database.query(...)
    reflective field access via getPopulatedFieldsAsMap() not tracked
  provenance offline_snapshot · confidence: parsed + heuristic

The parsed edges come from the default ANTLR pass over the Apex source; the blind-spot lines are shapes the parser explicitly flags rather than silently dropping. Treat the resolved edges as high-trust and the blind spots as prompts to read the source before you act.

How edge confidence works

Every dependency edge carries one of four tiers. The tier tells you how the edge was found, which is what governs how much to trust it. This is the per-edge confidence - distinct from a reasoning claim's confidence.

TierHow the edge was foundHow much to trust it
declaredSalesforce metadata states the dependency directly - FLS, layout, validation rule, record type, lookup / master-detailHighest - it is written in the XML
parsedANTLR/AST parse of Apex or XML parse of a Flow or formula - resolved field reads and writes, cross-class calls, field-level SOQLHigh - grounded in the real source
heuristicRegex/token backfill where the parser failed or the reference is only textualLower - can false-positive; spot-check before acting
partialA metadata family was not retrieved this refreshNot evidence of absence - "not checked", never "none"

Static analysis has hard blind spots, and sf-intelligence names them rather than papering over them:

  • Dynamic SOQL / SOSL strings - queries assembled at runtime (Database.query(someString)) reference fields the parser cannot resolve.
  • Reflective field access - getPopulatedFieldsAsMap(), getGlobalDescribe(), and dynamic get()/put() touch fields by name at runtime, invisibly to a static scan.
  • Cross-method dataflow - a value read in one method and written in another is not traced end to end, so some transitive field dependencies are not linked.

Because of these gaps, an empty result is reported as no static evidence found, never as "unused." A dependency finding describes a static shape in the retrieved metadata; it is not proof of what runs in production.

Coverage: what dependency analysis sees and misses

Metadata familyEdge confidenceCapturedNot captured
Layouts, field-level security, validation rules, record types, lookupsdeclaredDirect references from the retrieved XML
Flows & formulasparsedField reads/writes, subflow calls, formula field referencesWhich branch a given record takes (needs record data)
Apex - default ANTLR passparsedResolved field reads/writes, cross-class calls, field-level SOQLDynamic SOQL/SOSL strings, reflective field access, cross-method dataflow
Apex - regex backfill on parse failureheuristicTextual field / class mentions the parser missedFalse positives; confirm before acting
Any family the refresh skippedpartialReported as "not checked", never "none in org"

Run sfi.coverage_report to see which families your last refresh actually retrieved. A type listed under notModeled means it was not checked - so any absence-based answer over that type is only as strong as that coverage.

For change-specific blast radius examples, read Salesforce impact analysis. To list every place a single field is referenced, read where is a Salesforce field used. For broader org inventory, read Salesforce metadata analysis. For installation in an AI client, read Claude Salesforce MCP setup.

Trace dependencies before you change metadata.

Run a read-only refresh, then ask dependency questions in plain language.