recursive-trigger-prevention
Use when debugging or preventing recursive Apex trigger behavior, especially around self-DML, static guard flaws, Set<Id>-based deduplication, and legitimate re-entry scenarios. Triggers: 'trigger recursion', 'static boolean guard', 'recursive update', 'self DML', 'trigger firing multiple times'. NOT for general trigger-framework structure unless recursion is the actual design problem.
Best use case
recursive-trigger-prevention is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Use when debugging or preventing recursive Apex trigger behavior, especially around self-DML, static guard flaws, Set<Id>-based deduplication, and legitimate re-entry scenarios. Triggers: 'trigger recursion', 'static boolean guard', 'recursive update', 'self DML', 'trigger firing multiple times'. NOT for general trigger-framework structure unless recursion is the actual design problem.
Teams using recursive-trigger-prevention should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/recursive-trigger-prevention/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How recursive-trigger-prevention Compares
| Feature / Agent | recursive-trigger-prevention | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Use when debugging or preventing recursive Apex trigger behavior, especially around self-DML, static guard flaws, Set<Id>-based deduplication, and legitimate re-entry scenarios. Triggers: 'trigger recursion', 'static boolean guard', 'recursive update', 'self DML', 'trigger firing multiple times'. NOT for general trigger-framework structure unless recursion is the actual design problem.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
Use this skill when trigger behavior is correct once and wrong on the second pass. The objective is to prevent accidental recursion without suppressing legitimate processing. In Salesforce, recursion often comes from self-DML, after-save updates, or surrounding automation, and the classic static-boolean fix is usually too blunt. ## Before Starting - What actually causes the second execution: self-update, related-object update, Flow/workflow field update, or integration callback? - Is every repeated execution bad, or is some re-entry valid under certain records or transitions? - Do you have record-level identity available to guard by ID instead of suppressing the whole transaction globally? ## Core Concepts ### Static Boolean Guards Are Usually Overbroad A single static Boolean often stops more than recursion. It can suppress valid processing for later records in the same transaction or later phases that should still run. This is why backlog guidance explicitly calls out the flaw: it does not scale well to multi-record or multi-phase behavior. ### Record-Aware Guards Are Safer Set-based or map-based guards keyed by record ID or operation context are usually more precise. They let the system prevent duplicate processing for the same logical work item without globally silencing the handler. ### Guard Logic Must Match The Actual Recursion Source If the real issue is after-save self-DML, the guard should sit before that DML path. If the issue is a legitimate second pass only when a field truly changes, old/new delta checks may be more important than a static flag. ### Some Re-Entry Is Legitimate Not every second pass is a bug. Reparenting, staged enrichment, or chained updates can involve intended re-entry. Good recursion prevention blocks accidental loops, not all repeated execution. ## Common Patterns ### Set<Id>-Based Guard **When to use:** The same record should not be processed twice for the same logical step in one transaction. **How it works:** Store processed IDs in a static set and check membership before performing self-triggering work. **Why not the alternative:** A single static Boolean suppresses unrelated records too. ### Delta-Based Guard Clause **When to use:** Recursion should happen only if a meaningful field transition occurs. **How it works:** Compare `Trigger.oldMap` to `Trigger.new` and exit unless the relevant state actually changed. ### Framework-Level Guard Service **When to use:** The org already uses a trigger framework and needs consistent recursion rules. **How it works:** Centralize guard management so every handler does not reinvent incompatible static state. ## Decision Guidance | Situation | Recommended Approach | Reason | |---|---|---| | Self-DML on the same records is causing repeated after-update work | Set<Id>-based or context-aware guard | More precise than a global Boolean | | Processing should happen only on meaningful status changes | Delta check using old/new values | Often removes the need for broad static guards | | Org already has a trigger framework | Framework-level recursion service | Consistency and lower duplication | | Re-entry is partly legitimate | Narrow guard by record and condition | Avoid suppressing valid behavior | ## Recommended Workflow Step-by-step instructions for an AI agent or practitioner activating this skill: 1. Gather context — confirm the org edition, relevant objects, and current configuration state 2. Review official sources — check the references in this skill's well-architected.md before making changes 3. Implement or advise — apply the patterns from Core Concepts and Common Patterns sections above 4. Validate — run the skill's checker script and verify against the Review Checklist below 5. Document — record any deviations from standard patterns and update the template if needed --- ## Review Checklist - [ ] The actual recursion source is identified before choosing a guard. - [ ] Static Boolean guards are challenged and replaced when too broad. - [ ] Old/new delta checks exist where field transitions matter. - [ ] Guard state is record-aware when multiple records may be processed. - [ ] Legitimate re-entry scenarios are not accidentally blocked. - [ ] Recursion logic is centralized where the trigger framework allows it. ## Salesforce-Specific Gotchas 1. **A static Boolean can suppress valid work for later records in the same transaction** — it is rarely the safest long-term pattern. 2. **After-save self-DML is the classic recursion source** — the guard must sit before that path, not after it. 3. **Surrounding automation can re-enter Apex too** — recursion is not always caused by trigger code alone. 4. **A guard that is too broad becomes a data-loss bug** — silent skipped processing is still failure. ## Output Artifacts | Artifact | Description | |---|---| | Recursion review | Findings on recursion source, guard precision, and skipped-processing risk | | Guard recommendation | Choice of set-based, delta-based, or framework-level recursion prevention | | Trigger remediation pattern | Concrete guard placement guidance for self-DML or re-entry scenarios | ## Related Skills - `apex/trigger-framework` — use when recursion issues are inseparable from the broader handler architecture. - `apex/exception-handling` — use when recursive behavior is surfacing as transaction rollbacks or swallowed failures. - `apex/governor-limits` — use when recursion is also multiplying SOQL, DML, or CPU consumption.
Related Skills
xss-and-injection-prevention
Use when writing or reviewing Visualforce pages, Apex controllers, or LWC components that output user-supplied data, build dynamic queries, or construct HTTP responses. Triggers: 'XSS in Visualforce', 'SOQL injection vulnerability', 'how to encode output in Apex', 'JSENCODE Visualforce', 'open redirect prevention'. NOT for Apex CRUD/FLS enforcement (use soql-security or apex-crud-and-fls), NOT for Shield encryption (use shield-encryption-key-management), NOT for AppExchange security review process (use secure-coding-review-checklist).
recaptcha-and-bot-prevention
Use when configuring reCAPTCHA on Web-to-Case, Web-to-Lead, Experience Cloud forms, or Headless Identity flows, or when designing bot-mitigation strategies for Salesforce public-facing surfaces. Triggers: 'enable reCAPTCHA on Web-to-Case', 'bot spam submissions on my Experience Site', 'Headless Identity reCAPTCHA v3 setup'. NOT for AppExchange security review (use secure-coding-review-checklist), NOT for session-level login security policies (use session-management-and-timeout), NOT for IP-range-based access controls (use network-security-and-trusted-ips).
recursion-and-re-entry-prevention
Use when a record-triggered Flow re-fires on the same record because its own DML (or a downstream Flow's DML) re-satisfies the entry criteria — causing CPU-limit failures, duplicated side effects, or 'Maximum Trigger Depth Exceeded' errors. Triggers: 'flow infinite loop', 'flow re-firing on same record', 'flow updates field then runs again', 'flow A and flow B keep updating each other', 'maximum trigger depth exceeded record-triggered flow', 'flow recursion limit hit'. NOT for Apex trigger recursion (use apex/recursive-trigger-prevention) or for Loop element design inside a single Flow run (use flow/flow-loop-element-patterns).
record-triggered-flow-patterns
Use when designing or reviewing Salesforce record-triggered Flows, especially before-save vs after-save behavior, entry criteria, recursion avoidance, and when to escalate to Apex. Triggers: 'before save vs after save', '$Record__Prior', 'record-triggered flow', 'order of execution', 'flow recursion'. NOT for screen-flow UX or pure bulkification work when the trigger model is already correct.
flow-migration-from-trigger
Decide whether an existing Apex trigger should be rewritten as a Flow, and execute the migration safely. Covers the decision criteria (complexity, ownership, performance), side-by-side rollout, test-coverage parity, and the inverse case (recognize when Flow should stay Apex). NOT for migrating Process Builder / Workflow Rule to Flow (use those migration skills). NOT for brand-new automation decisions (use automation-selection.md).
trigger-framework
Use when writing, reviewing, or designing Apex triggers. Triggers: 'trigger', 'trigger handler', 'trigger framework', 'recursion', 'before insert', 'after update', 'one trigger per object'. NOT for Flow-based automation — use admin/flow-for-admins for declarative automation decisions.
trigger-and-flow-coexistence
Governance patterns for orgs where Apex triggers and record-triggered Flows both run on the same object. Covers field-write conflict prevention, single-entry-point consolidation, recursion guards across automation types, and automation inventory documentation. Use when inheriting a mixed-automation org, adding a Flow to an object that already has triggers, or resolving silent field-overwrite bugs. NOT for order-of-execution mechanics (use order-of-execution-deep-dive). NOT for trigger handler framework design (use trigger-framework). NOT for Flow-only design patterns (use record-triggered-flow-patterns).
opportunity-trigger-patterns
Use when building or reviewing Apex triggers on the Opportunity object — stage-change detection, amount rollups to Account, OpportunityTeamMember sync, or OpportunitySplit calculations. Trigger keywords: stage change automation, opportunity rollup, team member sync, split percentage, Trigger.oldMap stage comparison. NOT for generic trigger framework structure (use apex/trigger-framework) and NOT for Flow-based opportunity automation (use admin/flow-for-admins).
npsp-trigger-framework-extension
Use when extending the NPSP Trigger-Driven Trigger Management (TDTM) framework with custom Apex handler classes — covering class authorship, DmlWrapper return patterns, Trigger_Handler__c registration, load order, recursion guards, and test isolation. NOT for standard Apex triggers outside of NPSP, general trigger-handler framework design, or Nonprofit Cloud (NPC) which replaced NPSP in new orgs.
case-trigger-patterns
Use when writing Apex triggers on the Case object — specifically for invoking assignment rules programmatically, auto-associating entitlements in a trigger, handling merge trigger behavior on losing records, or understanding why milestone completion does not fire automatically when a case closes. Trigger keywords: 'case trigger', 'case assignment rule apex', 'entitlement auto-association trigger', 'case merge trigger', 'MasterRecordId case', 'Database.DmlOptions AssignmentRuleHeader', 'milestone not completing on case close'. NOT for generic trigger framework architecture — use apex/trigger-framework for that. NOT for configuring assignment rules in Setup — use admin/assignment-rules. NOT for SLA configuration or entitlement process design — use admin/entitlements-and-milestones.
apex-trigger-context-variables
Apex Trigger.new / Trigger.old / Trigger.newMap / Trigger.oldMap / Trigger.isInsert etc.: when each is populated, null-safety, recursion depth, trigger event matrix. NOT for trigger framework architecture (use apex-trigger-handler-framework). NOT for bulk patterns (use apex-bulkification-patterns).
apex-trigger-bypass-and-killswitch-patterns
Runtime mechanisms to disable Apex triggers without commenting out code: Custom Metadata kill switches via Trigger_Setting__mdt, Custom Permission gates via FeatureManagement.checkPermission, Hierarchy Custom Settings, and TriggerControl static-state bypass for nested operations. NOT for recursive-trigger-prevention (use apex-recursive-trigger-prevention) — bypass disables a handler intentionally; recursion guards prevent the same handler from re-entering itself.