SfSkills Domains Docs GitHub

Home / data / roll-up-summary-alternatives

roll-up-summary-alternatives

Use when native Roll-Up Summary fields are not enough and the design needs Flow, Apex aggregate, or DLRS-style alternatives for lookup or advanced summary scenarios. Triggers: 'roll up summary on lookup', 'build a lookup rollup', 'count child records on a lookup'. NOT for ordinary master-detail roll-ups that fit native limits — use apex/cross-object-formula-and-rollup-performance.

Open the skill folder on GitHub


Roll Up Summary Alternatives

Use this skill when stakeholders say "just add a roll-up field" and the platform answer is "not natively, at least not that way." Native Roll-Up Summary fields work when the relationship is master-detail and the summary is a count, sum, min, or max. Lookup relationships, other calculations, and high-churn parents need a different implementation, and each one has its own failure modes.


Before Starting

Gather this context before working on anything in this domain:


Questions to Ask Before Configuring

QuestionWhy it mattersWhat a good answer addsWhat proper configuration adds over just doing it
"Is the child related by master-detail or by lookup?"Native summaries need the master-detail field as summaryForeignKeyNative field when possible; a custom pattern only when requiredNo custom code where a native field would do
"Do children get merged, cascade-deleted, or undeleted with a parent?"Reparenting from a merge, cascaded deletes, and child undeletes do not fire child triggersA scheduled recompute that repairs totalsTotals that recover from paths the trigger never sees
"Will this run as a Flow, and must it handle deletes?"Record-triggered flows run on delete only before the record is deleted, and Flow has no undelete triggerA recount that excludes the record being deleted, plus a repair job for undeletesA Flow total that does not overcount by one on every delete
"How many children can one parent hold, and do loads arrive grouped by parent?"Skewed parents and ungrouped loads concentrate locks on the same parent rowsChild loads sorted by parent, and a recompute batch size that fitsFewer lock errors during loads
"Is SUM over many children going to run in one transaction?"SUM, MIN, MAX, and AVG count every aggregated row toward query-row limits; COUNT counts one row per groupScoped recomputes for very large parentsNo query-row limit errors on big parents
"Will we ever replace a native roll-up with a custom field?"Deleting a roll-up summary field through Metadata API purges it with no Recycle BinA backup of definitions and reports before the swapA reversible migration plan

What a proper configuration adds over a quick counter field: the total stays correct through deletes, merges, undeletes, and bulk loads, and there is a repair job when it does not.


Core Concepts

Native roll-up summary is the first choice

CustomField of type Summary supports summaryOperation values Count, Min, Max, and Sum, an optional summarizedField, summaryFilterItems, and summaryForeignKey, which "represents the master-detail field on the child" (Metadata API Developer Guide). The platform recalculates native summaries during the parent's save procedure: step 16 of the order of execution updates the parent, and step 17 updates a grandparent.

Lookup roll-ups need an alternative

OptionRuns whenStrengthsWatch out for
Apex trigger plus aggregate SOQLAfter insert, update, delete, undelete on the childFull control, bulk-safe, testableMerge reparenting, cascaded deletes, and child undeletes skip child triggers
Record-triggered FlowAfter save for create and update; before delete for deleteDeclarative ownershipNo after-delete or undelete trigger; a before-delete recount still sees the deleted row
DLRS (open-source package)Realtime, Scheduled, or Developer API modesDeclarative; adds Average, Count Distinct, Concatenate, First, LastA package to install, upgrade, and monitor
Scheduled recompute (Batch Apex or scheduled Flow)On a scheduleRepairs drift from any pathTotals are stale between runs

Triggers do not see every change

The Apex Developer Guide lists operations that don't invoke triggers, including cascading deletes ("only records that initiate a delete cause trigger evaluation") and cascading updates of child records reparented by a merge. After undelete runs only on top-level objects: undeleting an Account restores its Opportunities, but only the Account trigger runs. Any trigger-maintained total needs a recompute path.

Aggregate queries still cost query rows

All aggregate functions other than COUNT() and COUNT(fieldname) count each aggregated row as a query row. COUNT counts one row, or one per group with GROUP BY.


Common Patterns

Native roll-up on master-detail

Use the platform field. Worked XML in references/metadata-examples.md.

Apex recompute-from-source

Collect affected parent IDs from Trigger.new and Trigger.old (both old and new parents on reparent), run one aggregate query, write only parents whose value changed, and schedule the same method as a repair batch. Full trigger, service, batch, and test class in references/examples.md.

Flow-maintained summary

Use after-save flows for create and update. For delete, use a before-delete flow whose recount filters out $Record.Id. Pair it with a scheduled recompute for undeletes and merges.


Decision Guidance

SituationRecommended ApproachReason
Master-detail and count, sum, min, or maxNative roll-up summaryPlatform recalculates in the save procedure
Lookup, moderate volume, admin-ownedFlow (create and update after save, delete before delete) plus a scheduled recomputeFlow has no after-delete or undelete trigger
Lookup, high volume or complex filtersApex trigger with aggregate SOQL plus a repair batchBulk control and testability
Needs average, count distinct, concatenate, first, or lastDLRS or ApexNative summaries offer only Count, Min, Max, Sum
Records are merged or cascade-deletedAdd a scheduled recompute to any trigger or Flow approachThose paths skip child triggers
Replacing a native field with a custom oneBack up firstMetadata API purges deleted roll-up summary fields

  1. Classify the relationship and operation. Master-detail plus count, sum, min, or max goes native; stop there.
  2. List every path that changes a child. Insert, update (including reparent), delete, undelete, merge, cascade delete, bulk loads.
  3. Pick the engine. Use the option table above; size it against parent skew and daily load volume.
  4. Build recompute-from-source. One aggregate per transaction, write only changed parents, and a scheduled repair job. Start from references/examples.md.
  5. Test the paths. 200-row inserts, reparent, delete, undelete, and a repair run; then run python3 scripts/check_roll_up_summary_alternatives.py --manifest-dir force-app.
  6. Assign an owner. Name who watches repair-job results and who answers "why is this total wrong."

Review Checklist


Salesforce-Specific Gotchas

See references/gotchas.md. The two most often missed: merges and cascaded deletes change children without firing child triggers, and a before-delete flow still counts the record it is deleting.


Output Artifacts

ArtifactDescription
Summary decisionNative, Flow, Apex, or DLRS, with the reason
Rollup implementationTrigger, service, repair batch, and tests, or the Flow pair
Path coverage tableEach child-change path and what keeps the total right

Package files