SfSkills Domains Docs GitHub

Home / admin / compound-field-patterns

compound-field-patterns

Compound fields (Name, Address, Geolocation): SOQL access rules, DML semantics, component access in Apex/LWC, reporting column behavior, formula field restrictions.

Open the skill folder on GitHub


Compound Field Patterns

Activate when working with Salesforce compound fields — Name, Address, and Geolocation — in SOQL, Apex DML, LWC, or reports. Compound fields expose a single logical field (the compound) and N component fields (the parts). SOQL rules, DML behavior, and reporting differ in ways that trip up both humans and LLMs.

Before Starting

Questions to Ask Before Configuring

Ask these before opening Object Manager or writing the first query; each answer changes the field names your code targets, and an assistant that skips them writes code that compiles and saves the wrong column.

AskWhy it mattersWhat a good answer adds
"Are State and Country/Territory Picklists enabled here — and in every sandbox on the deploy path?"Decides whether writes target BillingState or BillingStateCode. Address.getStateCode() "returns the state code of this address if state and country/territory picklists are enabled in your organization. Otherwise, returns null" (apexrefguide.txt L199256–L199258)The exact field list every integration, Flow, and load file must target (gotcha 1)
"Which surfaces read this field — Apex, a report filter, a formula, a Flow, Data Loader export?"Only SOAP API, REST API, and Apex can see the compound value at all; every other surface needs componentsThe compound-vs-component decision per surface, from the matrix in references/well-architected.md (gotcha 7)
"Does the requirement need proximity — now, or plausibly next year?"DISTANCE/GEOLOCATION work only against a Location-type compound. Two independent decimal fields never qualify, and converting later is a data migration plus a field-name breaking changeA Location field type chosen at creation, before any data lands
"Is Person Accounts enabled, and can one transaction touch both record types?"Account.Name accepts a direct write on a business Account; on a Person Account it is "the concatenation of the FirstName, MiddleName, LastName, and Suffix of the associated person contact. You can't modify this value" (object_reference.txt L13262–L13266)An IsPersonAccount partition in the bulk code instead of a mixed-batch failure (gotcha 3)
"Do we need an address on an object that has no standard one?"Custom Address Fields is an org-wide enablement, and "Custom Address Fields can't be disabled. When enableCustomAddressField is set to true, you can't change the value to false" (api_meta.txt L113905–L113909)A deliberate, reviewed, one-way enablement — or a decision to use five text fields instead (gotcha 8)
"How many custom fields are left on this object?""Custom geolocation fields count as three custom fields towards your organization's limits: one for latitude, one for longitude, and one for internal use" (object_reference.txt L2874–L2876)The real field budget — see admin/data-model-documentation gotcha 7 for how to document it
"Is any validation rule or formula supposed to check 'the address is filled in'?""As of API version 20.0, validation rules can't have compound fields" (api_meta.txt L45369–L45370), and only ISBLANK, ISCHANGED, and ISNULL accept a compound at allA component-level rule set instead of one rule that will not compile (gotcha 9)

What a proper configuration adds over just reading and writing the field: every write lands on the column the org's flags actually make authoritative, proximity stays possible without a migration, and the rules and reports that need the address are expressed against components that exist on their surface.

Core Concepts

Name compound

Standard objects: Name is read-only compound; update FirstName, LastName, Salutation. Custom objects: Name is plain text unless defined as Person Name type.

Address compound

On Account (BillingAddress, ShippingAddress), Contact (MailingAddress, OtherAddress), Lead, User. The Address type extends Location. Components, verbatim from the Object Reference field table (object_reference.txt L2684–L2726):

ComponentTypeContact example
StreettextareaMailingStreet
CitystringMailingCity
StatestringMailingState
StateCodepicklistMailingStateCode — standard addresses only when state and country/territory picklists are enabled
CountrystringMailingCountry
CountryCodepicklistMailingCountryCode — always available on Custom Address Fields, picklist-gated on standard ones
PostalCodestringMailingPostalCode
Latitude / LongitudedoubleMailingLatitude / MailingLongitude
AccuracypicklistMailingGeocodeAccuracy — standard address fields on standard objects only, populated only once geocoded

Address compound fields are available in the SOAP and REST APIs in API version 30.0 and later.

Geolocation compound

CustomField of type Location (not "Geolocation" — that spelling is not in the FieldType enum, api_meta.txt L45760). Components are addressed by appending __Latitude__s / __Longitude__s to the field name "instead of the usual '__c'" (object_reference.txt L2915–L2917). Geolocation compound fields are available in the SOAP and REST APIs in API version 26.0 and later; Location is not an available custom field type on external objects (api_meta.txt L43233–L43245).

SOQL rules

-- Works: the compound in SELECT, through SOAP API, REST API, or Apex
SELECT Name, BillingAddress FROM Account

-- Fails: "Address fields can't be used in WHERE statements in SOQL"
SELECT Id FROM Account WHERE BillingAddress = :addr

-- Works: components
SELECT Id FROM Account WHERE BillingCity = 'SF' AND BillingStateCode = 'CA'

-- Works: the address compound used as a *location*, not as a filter value
SELECT Id, Name, BillingAddress FROM Account
WHERE DISTANCE(BillingAddress, GEOLOCATION(37.775,-122.418), 'mi') < 20
ORDER BY DISTANCE(BillingAddress, GEOLOCATION(37.775,-122.418), 'mi')
LIMIT 10

The last query is the guide's own sample (object_reference.txt L2836–L2841) and is the reason "no compound in WHERE" needs the qualifier: the compound is not filterable, but it is usable as a location operand inside DISTANCE. DescribeFieldResult.isFilterable() "erroneously returns true for address fields" (object_reference.txt L2950–L2951), so do not gate code on it.

Apex DML

// Works — components
update new Contact(Id = cid, MailingCity = 'SF');

// Fails — "Compound fields are read-only. To update field values, modify the individual field components."
update new Contact(Id = cid, MailingAddress = new Address(...));

// Reading: assign the parent to a typed variable first. Dot notation
// straight through the parent field does not compile.
Address addr = acct.BillingAddress;   // System.Address
String city  = addr.city;             // == addr.getCity()
Location loc = acct.MyLocation__c;    // System.Location
Double lat   = loc.latitude;

// Writing a geolocation: the __Latitude__s / __Longitude__s components
w.Warehouse_Location__Latitude__s  = 37.775;
w.Warehouse_Location__Longitude__s = -122.418;

Address and Location are also standard object names. In Apex, "always use Schema.Address instead of Address" for the object and System.Address for the compound field type; the same disambiguation applies to System.Location vs Schema.Location (apexrefguide.txt L199187–L199190, L221921–L221924).

LWC UI API

@wire(getRecord) returns compound and components; display via {v.fields.MailingAddress.displayValue} or each component individually.

Common Patterns

Pattern: Address update from form

Collect form fields, assign to component fields on a new SObject, DML. When State and Country/Territory Picklists are on, write the -Code component; see references/metadata-examples.md §5 for the load-file column list and references/examples.md Example 1 for the batch shape.

DISTANCE(location1, location2, 'unit') calculates the distance between two location values; GEOLOCATION(latitude, longitude) builds a location from coordinates and must be paired with DISTANCE. DISTANCE() is supported in SELECT, WHERE, and ORDER BY clauses; GEOLOCATION() is supported in WHERE and ORDER BY only. Neither is supported in GROUP BY. Use for store locators — see gotchas.md (Gotcha 6) for the four non-obvious query constraints and examples.md Example 2 for the working Apex pattern.

Pattern: Compute distance in Apex when SOQL cannot

DISTANCE/GEOLOCATION need a query. When both points are already in memory — a user's browser coordinates against a record you already hold — System.Location exposes the same maths without a second query: Location.newInstance(lat, lon), loc1.getDistance(loc2, 'mi'), and the static Location.getDistance(a, b, unit), all documented as "an approximation of the haversine formula" (apexrefguide.txt L221955–L221962). Use these instead of hand-rolling trigonometry; use SOQL DISTANCE whenever the filtering or sorting can happen in the database.

Pattern: Serialize compound to JSON

JSON.serialize(contact.MailingAddress) returns the compound object. Consuming code should use components, not the serialized blob as a key.

Decision Guidance

TaskApproach
Display full addressSelect compound, render via UI API or concatenate components
Filter by cityUse component field (BillingCity)
Update nameUpdate FirstName/LastName, not Name
Proximity searchDISTANCE on Geolocation compound
Report with address columnsUse component columns — the compound value is not accessible in the UI at all
Export addresses with Data LoaderSelect component fields; compound fields "cause error messages" on export
"Address is required" ruleValidation rule on components; compound fields are not allowed in validation rules
Distance rule in a workflow/approval/validation ruleDISTANCE formulas are supported there — the compound field on its own is not
  1. Fill templates/compound-field-patterns-template.md: the compound fields in scope, the three org flags (State and Country/Territory Picklists, Custom Address Fields, Person Accounts), and every surface that reads or writes the field. Answer the Questions table above into it.
  2. Resolve compound-vs-component per surface against the matrix in references/well-architected.md → Architectural Tradeoffs. Anything outside SOAP API, REST API, and Apex resolves to components.
  3. If a new field is needed, take the XML from references/metadata-examples.md §1 (Location field), §2 (CustomAddressFieldSettings) or §3 (AddressSettings) — not from admin/custom-field-creation, which covers the non-compound CustomField elements.
  4. Write the SOQL, the Apex reads and writes, and the Data Loader column mapping from §4–§6 of the same file. Keep the location field first in every DISTANCE call and the unit a literal.
  5. Run python3 scripts/check_compound_field_patterns.py --manifest-dir force-app/main/default. ERROR findings (compound in WHERE, compound DML assignment, DISTANCE without a unit) block the deploy; WARN and INFO findings need a written reason.
  6. Deploy with sf project deploy start --dry-run first, then verify with the describe call and the SOQL in §8–§9 — confirm MailingStateCode is populated, not just MailingState.
  7. Walk references/gotchas.md against the change before sign-off; each gotcha names the surface it breaks and the org flag that triggers it.

Review Checklist

Salesforce-Specific Gotchas

  1. State & Country Picklists change components. Adds BillingStateCode / BillingCountryCode alongside text versions; DML requires the code if picklist is enabled.
  2. Name on standard objects cannot be DML-assigned. Only on custom objects (where it's a plain text field anyway).
  3. Serialized compound in JSON integrations is not round-trippable. Always map to components explicitly.
  4. isFilterable() lies about address fields. The describe result reports true; SOQL rejects the filter. Do not build dynamic query builders on that flag.
  5. A custom geolocation field is three fields against the org limit, one in the UI, and absent from Schema Builder and dashboards.

The full set with reproduction and avoidance steps is in references/gotchas.md.

Output Artifacts

ArtifactDescription
Compound-access cheat sheetContext × field-type matrix
DML update templateComponent-assignment patterns
Geolocation query libraryDISTANCE patterns

Reference Files

FileRead it when
references/metadata-examples.mdYou are writing deployable metadata or queries: the Location CustomField XML with scale and displayLocationInDecimal, CustomAddressFieldSettings, AddressSettings, the SOQL set (compound, components, DISTANCE, GEOLOCATION), the Apex read/write patterns, the Data Loader column mapping, package.xml, retrieve/deploy, and the verification describe
references/gotchas.mdThe field saved and something downstream is wrong — a null -Code, an empty report column, a query the parser refuses, a describe flag that lies, or a formula that will not compile. Eleven behaviours with guide line citations
references/examples.mdYou want the scenarios end to end: a 30,000-record address batch under State and Country Picklists, a store-locator proximity query, and the compound-in-a-filter anti-pattern
references/well-architected.mdYou are justifying the design — the pillar mapping, the surface-by-surface compound-vs-component matrix, the three field-shape tradeoffs, and the sources every claim rests on
references/llm-anti-patterns.mdYou are reviewing AI-generated compound-field code and need the six failure modes with detection hints
templates/compound-field-patterns-template.mdWorkflow step 1 — the org-flag and surface inventory
scripts/check_compound_field_patterns.pyWorkflow step 5, before every deploy that touches an address, name, or geolocation field

Package files