I'm refactoring 4 workflow rules into before-triggers, and one thing I noticed is that I'm not saving a lot of time.

I'm investigating the possibility that this has to do with all 4 trigger handlers executing every time a Contact is saved within an execution context, whereas the "field updates" for 2 of the 4 "workflow rules" have "Re-evaluate Workflow Rules after Field Change" un-checked.

Does anybody know whether "Re-evaluate Workflow Rules after Field Change" behaves as a single massive execution-context-wide recursion-revention Boolean or if it behaves more like an execution-context-wide recursion-prevention Set<Id>?

That is ...

If I data-load 3 Contacts and therefore my automations are processing 3 Contacts, but then within the execution context, each of them results in a related Contact getting updated, so "potentially recursive" automations end up having a Trigger.new of size 6 ... do workflow rule field updates that already ran on the 3 original Contacts and have "Re-evaluate Workflow Rules after Field Change" turned off run again for the additional 3, or do they simply not evaluate again at all, because WR re-evaluation isn't that "clever?"

I want to avoid changing the way things actually work -- my admins and users shouldn't be able to tell that I did anything besides speed up the system.

I'd love to get away with a simple static Boolean to track whether my WR-replacement trigger handlers already ran, but I'll static Set<Id> if I need to.

  • 1
    be sure to review the Additional Considerations section of Triggers and Order of Execution - especially when using allornone=false (applies to API clients and some apex DML). If you have such use case, set<id> may not work for you in all use cases
    – cropredy
    Dec 11, 2019 at 20:46

1 Answer 1


The system is that "clever." It reevaluates the rules only for records that were changed (like a Set<Id>). There wouldn't be any point in checking the rules again if the records haven't changed. However, note that the checkbox doesn't go through the entire save process again; it simply reevaluates the rules and applies any further updates, and only after all rules are done evaluating (including any recursion) does the system proceed to the recursive trigger phase of updating records. Even then, Trigger.new will only include records that were updated as a result of a field update.

  • 1
    Thanks. Reading logs, I'm starting to suspect, too, that Salesforce doesn't "count" its own Workflow Rules' tracking & evaluation of whether to recurse or not in CPU time, whereas all that overhead totally counts when I write it. It's making it really hard to shave CPU time off an "inherently highly recursive" business process effectively. If I let WRs cause re-saves, I lose time to re-evaluating trigger code. If I move the WR behavior into trigger code, now I have to eat the CPU time to evaluate "fire or don't fire" on the remaining un-eliminable recursions. Very annoying.
    – k..
    Dec 11, 2019 at 17:16
  • 1
    @k.. Workflow Rules don't count against CPU time, though, just "wall time." I've found that, generally speaking, one should use either "all code" or "all configuration." Mixing the two tends to be the hardest route, because, as you've noticed, WR can easily double trigger CPU time.
    – sfdcfox
    Dec 12, 2019 at 4:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .