本文へ移動
cccskills
無料GitHub で公開

workflow-field-update-patterns

Cross-tool decision matrix for field-update automation in Salesforce — Before-Save Flow vs After-Save Flow vs Apex Trigger vs the deprecated Workflow Rule + Field Update. Covers the recursion / re-entrancy rules, governor cost per pattern (Before-Save flow is governor-free for the same record), the order-of-execution slot each tool occupies, and the Workflow-Rule-to-Flow migration playbook for field-update actions. NOT for the full record-save order of execution — use apex/order-of-execution-deep-dive. NOT for building the record-triggered Flow once the tool is chosen — use flow/record-triggered-flow-patterns. Trigger keywords: WorkflowFieldUpdate, reevaluateOnChange, onCreateOrTriggeringUpdate, doesRequireRecordChangedToMeetCriteria, failedMigrationToolVersion, Migrate to Flow, workflow-meta.xml, field update deprecated, double writer, second trigger pass.

インストール方法を見る

含まれるファイル(8)

  • SKILL.md26.2 KB
  • references/examples.md6.8 KB
  • references/gotchas.md17.2 KB
  • references/llm-anti-patterns.md5.2 KB
  • references/metadata-examples.md26.4 KB
  • references/well-architected.md7.1 KB
  • scripts/check_workflow_field_update_patterns.py22.8 KB
  • templates/workflow-field-update-patterns-template.md4.7 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Workflow Field Update Patterns

The most common automation question in Salesforce admin work: "I need to set field X to Y when condition Z." The answer depends on whether X is on the same record being saved (cheap, before-save flow), the parent (cross-object after-save), or a child (multi-record DML), plus volume, recursion risk, and whether the value can be derived as a formula instead of stamped.

This skill is the decision layer. It does NOT teach you to build the chosen tool — flow/flow-best-practices, apex/trigger-framework, and so on cover that. It also doesn't redefine the Salesforce order-of-execution sequence — see admin/order-of-execution.

What this skill IS: a decision matrix between the four field-update tools (formula, before-save flow, after-save flow, Apex trigger), plus the migration playbook for replacing legacy Workflow Rule field-update actions (deprecated as of late-2022).


Before Starting

  • Confirm the field-update need. If the value is purely a derivation of other fields on the same record, a formula field is the right answer — no automation needed at all. Don't reach for flow / trigger if formula fits.
  • Identify the target record. Same record being saved, parent, child, unrelated. Different targets need different tools.
  • Identify the volume. < 200 records per save event = standard paths. Bulk loads of 1M records hit Apex governor budgets that Flow can't always handle.
  • Inventory existing automation on the target object. Adding a new before-save flow to an object that already has 3 triggers and 2 flows is the recursion-risk territory.

Questions to Ask Before Configuring

Ask these before opening Flow Builder. Each one maps to a specific way this goes wrong later; skipping them produces automation that works on the demo record and diverges from the legacy behaviour it replaced.

AskWhy it mattersWhat a good answer adds
"Which record does the value land on — this one, its parent, its children, or an unrelated one?"Same-record is a free before-save Assignment; anything else is a DML and re-enters the save procedureThe tool, the order-of-execution slot, and whether a recursion guard is needed at all
"Is the target field one the platform computes during save — IsClosed, Amount with line items, ForecastCategory, ActivatedDate?"Before-save cannot write those; the workflow field update at step 11 couldThe choice between before-save and after-save, before the Flow is built and found to do nothing (§ 13)
"Does the existing rule carry reevaluateOnChange, a targetObject, or a workflowTimeTriggers block?"Each maps to something Flow does differently, or not at allThe real scope: one Flow, two Flows, or a cascade to rebuild by hand (§§ 11, 16)
"Which Apex triggers already run on this object, and how many times does each run today?"A field update forces a second update-trigger pass; removing it removes that passA measured before/after trigger-entry count instead of a post-deploy incident (§ 10)
"Does anything read this field later in the same transaction?"Step 3 and step 11 are eight steps apart; readers in between see different valuesThe list of downstream consumers that have to be re-tested, not just the field itself
"Is the source rule onCreateOnly, onCreateOrTriggeringUpdate, or onAllChanges?"It maps to a pair of Flow settings, and getting the pair wrong changes fire frequency without any errorThe correct recordTriggerType plus doesRequireRecordChangedToMeetCriteria, verified by parity rows 4 and 6
"Who owns the field, and what breaks if it stops being written for an hour?"Decides whether cutover can be a single deploy or needs a dual-write windowThe rollback plan, and whether the deploy can go out on a Friday

What a proper configuration adds over just building the Flow: the replacement fires on exactly the saves the old rule fired on, every Apex trigger on the object still runs the number of times its author assumed, and the field-history row after cutover proves which writer produced the value.


Core Concepts

The four field-update tools

ToolTargetGovernor costOrder-of-execution slot
Formula fieldSame record, derivedFree (computed at read time)N/A — not stored
Before-Save FlowSame record, stampedGovernor-free for same-record updatesAfter validation, before save
After-Save FlowSame record (re-DML), parent, child, unrelatedDML governor against limitAfter before-triggers + before-save flows
Apex Trigger (before-update)Same record, stampedSame as before-save flowSame slot (before-save flows are processed alongside)
Apex Trigger (after-update)Parent / child / unrelated via DMLDML governorAfter after-save flows

The standout: before-save flows updating the same record being saved are governor-free. They don't fire a second DML; they modify the in-flight record before commit. This is the cheapest field-update mechanism on the platform.

Same-record before-save vs same-record after-save

Updating a field on the SAME record being saved:

  • Before-save flow / trigger — modify the in-flight record; no second DML; no recursion possible (it's the same save event).
  • After-save flow / trigger — must issue an Update DML against the just-saved record; counts as a second DML; can recurse if the trigger that produced the update fires again on its own update.

The platform charges you (in DML, governor budget, recursion risk) to do the same work after-save that you can do free before-save. Before-save is the right choice unless you specifically need a value that's only computed after the initial save (record Id on insert is the canonical example — but lookup-relationship integrity often makes after-save the wrong shape too).

Recursion: the after-save trap

A record-triggered after-save flow that updates a field on the same record fires again on its own update. Without a guard, infinite loop — Salesforce's recursion-detection cuts it at around 16 levels with an exception. With a guard (a custom static variable, a field-set check, a "do nothing if X is already set" decision branch in the flow), the second invocation no-ops.

The cleanest guards:

  • isChanged(Field__c) decision in the flow's entry condition — only run if the field-being-updated changed.
  • Static Set<Id> recursion sentinel in Apex — track which records the trigger has already processed in this transaction.
  • Don't write the value if it already matches — decision branch before the Update Records element.

Order of execution overlap with other automation

Salesforce's published order-of-execution is a fixed 20-step sequence. The steps this skill touches, using the documented step numbers:

StepWhat runs
3Before-save record-triggered flows
4Before triggers
5System validation and custom validation rules
6Duplicate rules
7Record saved to the database, not yet committed
8After triggers
9–12Assignment, auto-response, workflow rules (11 — where Workflow Rule field updates fire), escalation
13Process Builder and workflow-launched flows, not in a guaranteed order — the one genuinely indeterminate slot
14After-save record-triggered flows
15Entitlement rules
16–17Roll-up summary fields recalculate on parent, then grandparent
19Commit

Before-save flows (3) and before-update triggers (4) are separate, ordered steps — the flow always runs first. The same holds for after triggers (8) and after-save flows (14): the trigger always runs first, with steps 9–13 in between. Neither pair is interleaved.

Field updates from flows can fire other before-save flows / triggers. Field updates from after-save automation re-enter the loop — this is the recursion source. Plan for it.

Workflow Rule field-update deprecation

Workflow Rules with Field Update actions stopped being creatable in new orgs and stopped accepting new Field Update actions on existing rules in late 2022. They still RUN in orgs that have them; they're not deleted. The migration target is record-triggered flow — typically before-save for same-record stamps, after-save for cross-object updates. The migration tool surfaces them in Setup; the mapping is straightforward.


Common Patterns

Pattern A — Same-record stamp via before-save flow

When to use. Stamp Account.Last_Reviewed_Date__c to TODAY when Account.Status__c = 'Active'. Same record, derived, no parent / child involvement.

Approach. Record-triggered flow on Account, before-save, entry condition Status__c = 'Active' AND ISCHANGED(Status__c). Single Update Records element setting Last_Reviewed_Date__c = {!$Flow.CurrentDate}. Done.

Why before-save. Free (no DML), no recursion possible.

Pattern B — Same-record stamp where formula would be enough

When to use. Opportunity.Display_Stage__c = "Won (" + TEXT(StageName) + ")" for a custom UI rendering.

Wrong instinct. Build a flow that stamps it on every save.

Right answer. Formula field. Computed at read time, no storage, no automation, no recursion, no stale-value risk.

If the formula approach can express it, that's the right answer. Reach for flow / trigger only when the value can't be expressed as a formula (depends on related-record state that formulas can't traverse, requires history that formulas don't have access to, needs to be settable by other automation downstream).

Pattern C — Cross-object update via after-save flow

When to use. When Case.Status__c = 'Closed', decrement the parent Account.Open_Cases__c by 1.

Approach. Record-triggered flow on Case, after-save (must be after-save — cross-object DML can't happen in before-save). Update Records element on the parent Account, decrementing the field.

Recursion guard. The Account update doesn't fire a Case trigger, so no Case-side recursion. But the Account-side automation may react. Account before-save flow that re-stamps a derived field on Account is fine; Account after-save flow that updates Account's own fields is the standard recursion territory.

Pattern D — Apex trigger when flow can't express the logic

When to use. Field update requires complex logic — a Schema describe call, a callout result, a Type.forName dispatch, a batched DML across multiple objects in one transaction.

Approach. Use templates/apex/TriggerHandler.cls as the base. Recursion guard via static Set<Id>. Bulkify; the trigger fires for batches up to 200 (or 2000 for Platform Event triggers).

The honest cost: Apex requires test coverage, deploy via metadata, admin can't edit it. Use only when flow can't express it.

Pattern E — Migrating Workflow Rule field updates

When to use. Existing org with Workflow Rules that include Field Update actions; modernizing to flow.

Per-rule mapping.

Workflow conceptFlow equivalent
Rule trigger "created" / "edited" / "created and any time edited"Record-triggered flow start setting matching the trigger choice
Rule criteriaFlow entry condition
Field Update actionUpdate Records element setting the same field
Re-evaluate workflow rules after field changesDefault flow behavior (chains downstream automation)

Where each operation lands. WorkflowFieldUpdate.operation has six values and they do not all have a Flow equivalent. The full element-by-element mapping — including entry criteria, trigger type and time triggers — is the table in references/metadata-examples.md.

operationReplacement
LiteralAssignment with a typed literal value
Formulaformulas resource + Assignment by elementReference
NullAssignment against an empty value; there is no null operator
LookupValueAssignment of the Id; only User was ever supported here (§ 15)
NextValue / PreviousValueNo equivalent — rebuild as an explicit transition map (§ 12)

Migration order. Use Salesforce's Migrate to Flow tool (Setup → Workflow Rules → Migrate to Flow). It produces a draft flow that you review, test, activate, and only THEN deactivate the original Workflow Rule. Don't deactivate first; the gap leaves the field unstamped. Ship the activation and the deactivation as one deploy — references/metadata-examples.md has the cutover manifest and the field-history verification query.


Decision Guidance

SituationApproachReason
Value is purely derived from other fields on same recordFormula fieldNo automation; no recursion; no governor cost
Stamp same-record field on saveBefore-save flowGovernor-free; no recursion possible
Cross-object update (parent / child / unrelated)After-save flowCross-object DML requires after-save context
Logic is too complex for flow (callouts, Schema describe, etc.)Apex triggerUse TriggerHandler template + recursion guard
Existing Workflow Rule field updateMigrate to record-triggered flowWorkflow Rule field updates are deprecated for new actions
Volume > 100K records on a single save eventApex with explicit bulkificationFlow governor budget can be tight at extreme bulk
Field update fires on every record save indiscriminatelyAdd ISCHANGED() entry conditionOtherwise the automation runs on every save, even no-op
After-save flow updating the same record's other fieldisChanged() guardDefault behavior recurses
Field update produces a value that triggers other automationDocument the chainEach automation level adds governor pressure
Multiple admins each adding their own field-update flowConsolidate into one flow per object"One flow per save event" prevents per-flow overhead and ordering ambiguity

Recommended Workflow

  1. Inventory before designing. Retrieve Workflow with the wildcard manifest in references/metadata-examples.md, then run python3 scripts/check_workflow_field_update_patterns.py --manifest-dir force-app/main/default. The inventory block gives the counts that set the scope: field updates per object, reevaluateOnChange flags, targetObject cross-object updates, time triggers, and rules that already defeated the Migrate to Flow tool.
  2. Rule the field out of automation entirely. If the value is a function of same-record fields at read time, it is a formula field — references/examples.md Example 4 has the CustomField XML and the one behavioural difference (formulaTreatBlanksAs) to check before deleting the automation it replaces.
  3. Answer the seven questions above and route. automation-selection.md Q2 (same record, under ~10s) → before-save Flow; Q4/Q5 (crosses objects, linear) → after-save Flow; Q3 (callout retry, savepoints, recursive same-object DML) → Apex on templates/apex/TriggerHandler.cls. flow-pattern-selector.md Q3 confirms before-save vs after-save; Q5 routes a time trigger to a scheduled path.
  4. Build from the matching example, not from scratch. references/metadata-examples.md Example 2 (before-save Flow), Example 3 (after-save, targetObject case), Example 4 (Apex beforeUpdate excerpt). Map every legacy element through the table there; anything with no row is a design decision to record, not to skip.
  5. Fill templates/workflow-field-update-patterns-template.md. Sections 3 and 4 are the ones that catch migrations: the element-by-element legacy mapping, and the measured trigger-entry count per save before and after the cutover.
  6. Run the checker against the change, not just the org. Re-run check_workflow_field_update_patterns.py --manifest-dir <tree> on the branch. Zero ERRORs is the deploy gate; the double-writer WARN firing means the cutover is only half-built.
  7. Parity-test, then cut over in one deploy. Run the seven-row table from references/metadata-examples.md with the legacy rule live, then with it deactivated — identical results both times. Deploy the Active Flow and <active>false</active> together, then confirm with the field-history query.

Review Checklist

  • Formula field was considered before reaching for flow / trigger.
  • Before-save flow used when same-record stamp doesn't need post-save context.
  • After-save flow / trigger has a recursion guard (ISCHANGED or static set).
  • Entry condition scopes the automation to relevant changes only.
  • Workflow Rule field updates have been migrated (or migration is planned with deactivation gating).
  • One flow per object per save event (no fragmented per-team flows that all fire).
  • Apex trigger uses templates/apex/TriggerHandler.cls if a trigger is the right answer.
  • check_workflow_field_update_patterns.py --manifest-dir reports zero ERRORs on the branch.
  • Every legacy element has a row in the mapping table, including reevaluateOnChange, targetObject and workflowTimeTriggers — or a recorded decision that it is intentionally dropped.
  • Trigger-entry count per save measured before and after the cutover, and any difference accepted in writing.
  • Target field checked against the "not updateable in before triggers" list before choosing before-save.
  • Parity table run twice — legacy rule live, then deactivated — with identical results.
  • Flow activation and rule deactivation ship in the same package.xml.
  • Post-deploy field-history query returns a new row for the field.

Salesforce-Specific Gotchas

  1. Before-save flows are governor-free for same-record updates. Don't re-implement same-record stamps in after-save. (See references/gotchas.md § 1.)
  2. After-save flow updating the same record recurses without a guard. Default behavior; explicit guard required. (See references/gotchas.md § 2.)
  3. Workflow Rule field updates are deprecated for new actions as of late 2022 — migrate or accept they're frozen. (See references/gotchas.md § 3.)
  4. Formula fields are computed at read time, not stored. Reports / dashboards can sort / filter on them but at query cost. (See references/gotchas.md § 4.)
  5. Before-save flows run at step 3, before-update triggers at step 4 — the order is fixed and documented, so a before trigger always sees values the before-save flow already wrote, and can overwrite them. (See references/gotchas.md § 5.)
  6. Cross-object update from a flow fires the target object's automation. Plan the chain. (See references/gotchas.md § 6.)
  7. Multiple flows on the same object firing on the same save event all run; ordering is not guaranteed across flows. (See references/gotchas.md § 7.)
  8. ISCHANGED() is true on insert — the value changed from null. Scope the trigger setting deliberately. (See references/gotchas.md § 8.)
  9. Migrate to Flow produces a draft and leaves the source rule active. Both writers run until you deactivate it. (See references/gotchas.md § 9.)
  10. Retiring a field update deletes a second update-trigger pass that no Apex author wrote down; trigger behaviour changes in a deploy containing no Apex. (See references/gotchas.md § 10.)
  11. reevaluateOnChange restarts every rule on the object, up to five cascades. Flow has no equivalent element. (See references/gotchas.md § 11.)
  12. NextValue / PreviousValue walk the picklist's own order and have no Flow counterpart; rebuild as a transition map. (See references/gotchas.md § 12.)
  13. A before-save Flow cannot write the fields the system computes during save — the workflow field update at step 11 could. (See references/gotchas.md § 13.)
  14. In the pass after a field update, Trigger.old holds pre-update values, not what the user submitted. (See references/gotchas.md § 14.)
  15. LookupValue only ever supported User, despite lookupValueType advertising Queue and RecordType. (See references/gotchas.md § 15.)
  16. A rule with both immediate and time-dependent field updates becomes two Flows, in different save-time slots. (See references/gotchas.md § 16.)

Output Artifacts

ArtifactDescription
Field-update tool decisionFormula / before-save flow / after-save flow / trigger, with rationale
Recursion-guard implementationISCHANGED / static set / decision-branch — explicit and tested
Entry condition expressionScope the automation to relevant changes
Workflow Rule migration planIf applicable: Migrate-to-Flow output, sandbox test, deactivation gating

Reference Files

FileRead it when
references/metadata-examples.mdWriting the deployable XML: the legacy Workflow file, the before-save and after-save Flow replacements, the Apex variant, the element-by-element mapping table, package.xml, retrieve/deploy commands, the cutover sequence and the parity test table
references/gotchas.mdSixteen platform behaviours that make a correct-looking field update wrong — the second trigger pass, reevaluateOnChange, NextValue, before-trigger write restrictions, Trigger.old, LookupValue, time triggers
references/examples.mdLooking for a worked case: after-save done wrong, cross-object counter, a WFR migration with the inventory commands, the formula-field replacement with its CustomField XML, the Apex-only case
references/llm-anti-patterns.mdReviewing generated field-update advice — the eight failure modes assistants reproduce from pre-2022 training data
references/well-architected.mdFraming the choice against Reliability and Operational Excellence, and for the full source list with line references
templates/workflow-field-update-patterns-template.mdBefore building or migrating any field update worth reviewing — the decision record, the legacy mapping table, and the cutover checklist
scripts/check_workflow_field_update_patterns.pyInventorying an org, and as the pre-deploy gate on a migration branch (--manifest-dir)

Related Skills

  • admin/process-automation-selection: Use for the tool-choice decision record and the save-procedure gotchas this skill cross-references rather than restates — step 11's second trigger pass, the recursive-save skip, failedMigrationToolVersion.
  • apex/order-of-execution-deep-dive: Use when the question is the full 20-step sequence rather than the field-update slice of it.
  • flow/workflow-rule-to-flow-migration: Use when migrating a whole rule, including alerts, tasks and outbound messages. This skill covers only the field-update action.
  • admin/flow-for-admins: Use for the Flow XML surface in general — element ordering, filters vs filterFormula, status handling, activation.
  • flow/record-triggered-flow-patterns: Use to build the replacement Flow once the slot is chosen.
  • flow/recursion-and-re-entry-prevention: Use when the after-save variant needs a guard beyond an entry condition.
  • flow/flow-time-based-patterns: Use when the source rule carried workflowTimeTriggers and the replacement needs scheduled paths.
  • apex/trigger-framework: Use when the decision tree routes to Apex; canonical base at templates/apex/TriggerHandler.cls.
  • flow/flow-error-notification-patterns: Use for fault handling on the after-save variant's DML.
  • admin/approval-processes: Use when the field update is an approval action rather than a rule action — the same WorkflowFieldUpdate component, a different owner.
  • admin/formula-fields: Use when the answer is no automation at all.
  • apex/dynamic-apex: Use when the Apex variant needs Schema describe calls.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use this skill when writing test-first, behavior-driven acceptance criteria in Given/When/Then format for a Salesforce user story. Covers happy path, edge cases, negative paths, permission boundaries, and data-state preconditions so the AC block can drive UAT scripts and Apex test design downstream. Trigger keywords: given when then, gherkin, behavior driven AC, test first acceptance criteria, scenario outline, BDD acceptance criteria. NOT for the user-story format itself (use admin/user-story-writing-for-salesforce). NOT for UAT script writing (use admin/uat-test-case-design). NOT for Apex test method generation (use agents/test-class-generator). NOT for high-level UAT planning (use admin/uat-and-acceptance-criteria). More triggers: acceptance criteria record, ac_id, req_id on a criterion, artefact under test, negative case for a rule-type requirement, no-match fall-through criterion, oracle for a Then clause, test type apex flow manual, criteria linter, check_ac_format.py, --manifest-dir.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Task and Event objects: polymorphic WhatId/WhoId, Activity object model, ActivityHistory vs OpenActivity, activity timeline customization, bulk task creation, Einstein Activity Capture boundaries. NOT for turning on EAC or calendar sync — use admin/einstein-activity-capture-setup. NOT for Email-to-Case — use admin/case-management-setup. Covers ActivitiesSettings metadata, enableActivities, shared Task/Event custom fields and FLS, TaskStatus value sets, Shared Activities and TaskRelation/EventRelation, recurring and child activities, and partial-success bulk DML on Task.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Design Invocable Apex actions that return deterministic, agent-friendly errors instead of surfacing raw exceptions to the LLM. NOT for authoring the action itself — @InvocableMethod schema, labels, security context — use agentforce/custom-agent-actions-apex. NOT for the Apex tests that force each error branch — use agentforce/agent-action-unit-tests.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Use when designing how an Agentforce agent extracts structured input parameters (slots) from a user's natural-language utterance to invoke an action. Triggers: 'agent extract date from user', 'agent action argument extraction', 'agentforce slot filling', 'agent invocable input mapping', 'agent fails to fill required parameter'. NOT for action authoring (use agentforce/agent-actions) or for prompt-template variable binding (use agentforce/prompt-builder-templates).

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Apex test patterns for @InvocableMethod agent actions: per-reason-code branch coverage, bulk safety, callout mocking, deterministic assertions. NOT for testing whether the agent routes to the right topic or answers well — use agentforce/agent-testing-and-evaluation. NOT for designing the error envelope the tests assert on — use agentforce/agent-action-error-handling.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Designing or reviewing Agentforce actions: Flow actions, Apex invocable actions, prompt-template actions, action naming, input and output contracts, confirmation requirements, and safe error behavior. Triggers: 'agent actions', 'build an agent that can look up an order', 'make the agent able to check order status', 'give the agent a capability', 'agent that can retrieve a record', 'flow action for agent', 'agent invocable action', 'action schema design'. NOT for writing the Apex class itself — use agentforce/custom-agent-actions-apex. NOT for the reason_code error envelope that stops an agent retry loop — use agentforce/agent-action-error-handling.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

PranavNagrecha のスキルをすべて見る

このスキルの問題を報告する