Row-level formulas in Data Cloud are the easiest way to make a model “just work” — and the easiest way to torch your refresh budget. Most teams discover the cost only after the credit invoice arrives.
This is a field guide to where they break, written for the architect who already understands DMOs, calculated insights, and streaming ingest.
The seduction
You have an Individual DMO and an Engagement DMO. Marketing asks for LoyaltyScoreNormalized. You add a row-level formula on the unified profile, push to a segment, and ship. Done in twenty minutes.
Six weeks later the refresh job that used to take eight minutes is taking ninety, segment activations are missing the 6 AM window, and someone forwards you the FinOps report.
Row-level formulas are evaluated every time a DMO row is materialized into the unified graph. That is not the same as evaluated once per ingest. If you have streaming ingest plus a nightly identity resolution job plus an ad-hoc segment refresh, the same formula fires three times.
Pitfall 1: nested formulas across DMOs
The most expensive shape is a row-level formula that references a field on a related DMO — which itself is a row-level formula.
// On UnifiedIndividual__dlm
// Field: PropensityTier__c
// Formula:
CASE(
TEXT(ssot__EngagementProfile__r.PropensityScore__c),
"HIGH", "A",
"MED", "B",
"LOW", "C",
"UNKNOWN"
)
PropensityScore__c is itself a row-level formula bucketing RawScore__c. Now every unified individual row triggers a related-record materialization that triggers another formula. At 40M unified rows this is a 2-3x multiplier on identity resolution runtime.
Fix: push one of the two formulas to a Calculated Insight. CIs run on a schedule, store results, and stop re-evaluating downstream.
Pitfall 2: TEXT() on dates inside CASE
Sounds harmless. It is not.
// Bad
CASE(TEXT(MONTH(LastPurchaseDate__c)), "1", "Jan", ...)
// Good
CASE(MONTH(LastPurchaseDate__c), 1, "Jan", ...)
The string-cast variant disables the columnar pruning that Data Cloud uses to skip unaffected partitions on incremental refresh. You go from a 4% partition scan to a full table scan. Refresh time is bounded by the worst formula in the DMO.
Pitfall 3: formulas that look like joins
IF(
ssot__Account__r.Segment__c = "Enterprise"
&& ssot__Account__r.Region__c = "EMEA"
&& Amount__c > 100000,
"ENT-EMEA-LARGE",
"OTHER"
)
This is a join. Express it as one and let the engine plan it:
- Build a Calculated Insight that selects from the Account DMO with the segment + region predicate.
- Materialize the result as a derived DMO.
- Reference the derived DMO from your segment directly.
Calculated Insights run on Iceberg under the hood since the 2026 Spring update — they are cheaper than row-level formulas by 5-10x at scale.
Pitfall 4: blind reuse from CRM Analytics habits
Architects coming from CRM Analytics treat row-level formulas as free. In CRM Analytics they effectively are — the dataflow materializes them once. In Data Cloud the unified graph is queried far more often than a dataflow runs, and every query pays the formula cost.
Internal-link sanity: if your team is still mixing the two mental models, the Data Cloud data model fundamentals is worth re-reading.
Pitfall 5: NULL handling that fires twice
A common pattern:
IF(
ISBLANK(Score__c),
0,
IF(Score__c > 80, 1, 0)
)
The engine evaluates Score__c twice. With a nested CASE and three referenced fields you can quadruple cost. Use BLANKVALUE:
IF(BLANKVALUE(Score__c, 0) > 80, 1, 0)
Decision rule
A simple rubric we use in client reviews:
- Row-level formula is fine if: single DMO, no related-record traversal, no other row-level formula in the same DMO, segment cardinality < 1M, formula returns a primitive.
- Move to Calculated Insight if: any cross-DMO reference, any aggregation, fan-out > 10x, or used in three or more segments.
- Move to upstream ETL if: the source system can compute it cheaper, or the field is used in identity resolution.
Monitoring it
The Data Cloud Setup Audit object exposes refresh stats per DMO. Pull them.
List<DataCloudRefreshStat> stats = [
SELECT DmoApiName, DurationSeconds, RowsProcessed, CreditsConsumed
FROM DataCloudRefreshStat
WHERE RunDate = LAST_N_DAYS:7
ORDER BY CreditsConsumed DESC
LIMIT 20
];
for (DataCloudRefreshStat s : stats) {
System.debug(s.DmoApiName + ': ' + s.CreditsConsumed + ' credits / '
+ s.DurationSeconds + 's');
}
If a single DMO’s credit consumption is rising faster than its row count, you have a formula problem.
UX note
If your marketing team is the one adding formulas through the Data Cloud builder, gate the UI with a permission set that hides the row-level formula option for non-architects. They can still propose them via a custom request component on the DMO record page. Cheaper than apologies.
Bottom line
- Row-level formulas are a tax, not free.
- Nested formulas across DMOs and
TEXT()-on-date patterns are the two highest-leverage things to refactor first. - Calculated Insights are now cheaper per row than row-level formulas in almost every shape that matters.
- Watch credit-per-row trend, not raw credit total.
- Restrict who can add formulas at the builder level — governance beats cleanup.