The quick version: a roll-up summary field counts or aggregates child records, and it only works across a master-detail relationship. Four operations, one direction, up to 25 per object by default. If your relationship is a lookup, the answer is a flow, Apex, or converting the relationship, and converting the relationship has consequences you need to read first.
What it does
A roll-up summary lives on the master object and aggregates a field on its detail records. The operations are COUNT, SUM, MIN and MAX. COUNT needs no target field. SUM works on number, currency and percent fields. MIN and MAX also accept date and date/time.
Master-detail only, with a few standard exceptions
The relationship must be master-detail. That is the rule, and the reason is deletion: the platform can keep the aggregate correct because deleting a master deletes its details, and a detail record cannot be reparented casually.
Salesforce provides a handful of standard relationships that behave the same way without being declared master-detail. Account rolling up Opportunities is the well-known one, and Opportunity rolling up its line items is another. These are built in, not something you can replicate on your own objects.
Filter criteria, and what it will not filter on
A roll-up can be restricted to children matching criteria, which is where most of the useful ones live. “Sum of Amount where Stage equals Closed Won” is a roll-up. “Count of open cases” is a roll-up.
The filter cannot use:
- Long text area or multi-select picklist fields
- Another roll-up summary field on the child
- A formula field containing a cross-object reference
- A formula field using
TODAY(),NOW()or other dynamic date functions - Encrypted fields
The dynamic date restriction catches people building “sum of amounts in the last 30 days”. The platform will not accept it, because a roll-up is stored and a date-relative filter would need constant recalculation of records that did not change. The workaround is a stored date band on the child, refreshed by a scheduled process.
The 25 per object limit
Twenty-five roll-up summary fields per object by default. Salesforce will raise it on request, to a documented ceiling, and the request is routine rather than exceptional. Before asking, check whether half of yours are near duplicates that a single roll-up plus a formula could replace.
Recalculation behaviour
Roll-ups update in the same transaction as the child change. That has two visible effects.
First, the parent is locked while the child is saved. Bulk loading thousands of children that share a small number of parents produces row lock contention, and the fix is to sort the load by parent so that records touching the same parent land in the same batch.
Second, the parent record’s own automation fires. A roll-up change can trigger the parent’s record-triggered flows, workflow rules and Apex triggers. This is the usual cause of a flow firing on a record nobody edited.
There is a manual recalculation control on the field detail page. Use it after changing the filter criteria, after a data fix that bypassed normal save behaviour, and after converting a relationship. It runs asynchronously and can take a long time on a large object, and it is queued behind other org processes rather than immediate.
Frequently asked
Can a roll-up summarise a formula field on the child? Yes, provided the formula does not contain a cross-object reference or a dynamic date function. The same restrictions that apply to the filter apply to the summarised field.
Can I roll up across two levels? Only by stacking. A roll-up on the middle object, then a roll-up on the top object that sums the middle object’s roll-up. Salesforce permits this, and it recalculates in order.
Does a roll-up count against storage? Yes. Unlike formula fields, roll-up values are stored on the record.
Why is my roll-up showing zero after a data load? Loads that create children without triggering normal save behaviour, or a filter that no longer matches, are the usual causes. Run the manual recalculation and check the filter criteria against actual child values.
