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).

Best use case

apex-trigger-context-variables is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

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).

Teams using apex-trigger-context-variables 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

$curl -o ~/.claude/skills/apex-trigger-context-variables/SKILL.md --create-dirs "https://raw.githubusercontent.com/PranavNagrecha/AwesomeSalesforceSkills/main/skills/apex/apex-trigger-context-variables/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/apex-trigger-context-variables/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How apex-trigger-context-variables Compares

Feature / Agentapex-trigger-context-variablesStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

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).

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

# Apex Trigger Context Variables

Activate when writing or reviewing an Apex trigger or a trigger handler method that consumes Trigger context variables. Each variable (`Trigger.new`, `Trigger.old`, `Trigger.newMap`, `Trigger.oldMap`, `Trigger.isExecuting`, the event booleans) is populated only in specific events; using one in the wrong event causes `NullPointerException` or wrong semantics.

## Before Starting

- **Memorize the context matrix.** `Trigger.old` and `Trigger.oldMap` are null in `before insert` and `after insert`. `Trigger.newMap` is null in `before insert` (records have no Id yet).
- **Know the delete semantics.** In `before delete` / `after delete`, only `Trigger.old` and `Trigger.oldMap` are populated. `Trigger.new` is null.
- **Guard recursion.** Triggers can re-enter; a static `Set<Id> processedIds` or a framework flag is mandatory for trigger-causing-trigger scenarios.

## Core Concepts

### The event matrix

| Event | new | newMap | old | oldMap |
|---|---|---|---|---|
| before insert | ✓ | null (no Id) | null | null |
| after insert | ✓ | ✓ | null | null |
| before update | ✓ | ✓ | ✓ | ✓ |
| after update | ✓ | ✓ | ✓ | ✓ |
| before delete | null | null | ✓ | ✓ |
| after delete | null | null | ✓ | ✓ |
| after undelete | ✓ | ✓ | null | null |

### Modifying vs reading

`Trigger.new` records are **read-write** in `before` events (mutate fields directly). In `after` events, `Trigger.new` is read-only — attempts to modify throw. Updates in `after` require explicit DML on a separate list.

### Recursion and re-entry

Updating a record inside its own trigger re-fires the trigger. Guard with a framework-level static boolean or an ID set.

### `Trigger.size`

Scalar count — useful for bulk heuristics, but prefer `Trigger.new.size()`.

## Common Patterns

### Pattern: Before-update field stamping

```
for (Account a : Trigger.new) {
    Account oldA = Trigger.oldMap.get(a.Id);
    if (a.Industry != oldA.Industry) a.Industry_Changed_On__c = Datetime.now();
}
```

### Pattern: After-insert related-record creation

```
List<Contact> defaults = new List<Contact>();
for (Account a : Trigger.new) defaults.add(new Contact(AccountId = a.Id, LastName = 'Primary'));
insert defaults;
```

### Pattern: Before-delete gate

```
for (Account a : Trigger.old) {
    if (a.Is_Protected__c) a.addError('Cannot delete protected account');
}
```

## Decision Guidance

| Need | Access |
|---|---|
| Read new values, no Id needed | `Trigger.new` |
| Need Id (after insert and beyond) | `Trigger.newMap` |
| Compare old vs new | `Trigger.new` + `Trigger.oldMap.get(record.Id)` |
| Delete validation | `Trigger.old` / `Trigger.oldMap` |
| Determine context programmatically | `Trigger.isInsert`, `Trigger.isBefore`, etc. |

## Recommended Workflow

1. Decide trigger events (before/after × DML).
2. Consult the event matrix; confirm which context variables are populated.
3. Route each event to a dedicated handler method — never monolithic trigger body.
4. For before-update, pair `Trigger.new` iteration with `Trigger.oldMap.get(rec.Id)` lookup.
5. Add recursion guard via framework static flag.
6. Bulk-safe everything: no SOQL/DML in loops.
7. Unit test each event with `Test.startTest()` and explicit record setup.

## Review Checklist

- [ ] Correct context variable per event (not relying on null-populated ones)
- [ ] Null-safe access for oldMap in before-insert / after-insert
- [ ] Handler methods split by event
- [ ] Recursion guard in place
- [ ] Bulkified: no per-record SOQL/DML
- [ ] Before events mutate `Trigger.new`; after events use DML on new lists
- [ ] Tests cover each event with bulk collections (200+)

## Salesforce-Specific Gotchas

1. **`Trigger.newMap` is null in before-insert.** Records have no IDs yet; you cannot index by Id until after-insert.
2. **Modifying `Trigger.new` in after events throws.** Use a separate DML pass.
3. **`Trigger.old` is NOT populated in insert contexts.** Default to null checks for pre-existing state.

## Output Artifacts

| Artifact | Description |
|---|---|
| Event matrix reference | Quick-lookup table for which variable in which event |
| Handler template | Skeleton trigger + handler class |
| Recursion guard class | Framework static boolean |

## Related Skills

- `apex/apex-trigger-handler-framework` — framework architecture
- `apex/apex-bulkification-patterns` — bulk-safe DML
- `apex/apex-async-patterns` — async DML patterns when sync unsafe

Related Skills

apex-managed-sharing-patterns

8
from PranavNagrecha/AwesomeSalesforceSkills

Grant row-level access programmatically via __Share records when declarative sharing rules cannot express the policy. NOT for OWD, role hierarchy, or criteria-based sharing rule design.

lwc-imperative-apex

8
from PranavNagrecha/AwesomeSalesforceSkills

Call Apex methods imperatively from LWC — on button click, lifecycle hooks, or conditional logic. Covers import syntax, cacheable vs non-cacheable, async/await patterns, error handling, loading states, and Promise.all. NOT for wire service (use wire-service-patterns) and NOT for testing Apex mocks (use lwc-testing).

dataweave-for-apex

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when transforming structured data inside Apex — CSV → JSON, XML → SObject list, JSON → flattened CSV, or schema-mapping a third-party payload to a Salesforce model — and the existing options (`JSON.deserialize`, `Dom.Document`, hand-written loops) are getting unwieldy. Triggers: 'apex transform csv json xml without external library', 'system.dataweave script', 'salesforce native dataweave apex execute', 'transform xml to sobject apex no mulesoft', 'json reshape salesforce apex script'. NOT for MuleSoft Anypoint DataWeave running off-platform (use mulesoft-anypoint-architecture), NOT for Apex JSON serialization basics (use apex-json-serialization), NOT for Bulk API CSV ingest (use bulk-api-2-patterns).

record-triggered-flow-patterns

8
from PranavNagrecha/AwesomeSalesforceSkills

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-runtime-context-and-sharing

8
from PranavNagrecha/AwesomeSalesforceSkills

Decide and audit the security boundary a Flow runs at — System Context With Sharing, System Context Without Sharing, or User Context — plus the per-element runInMode override and the implications for sharing rules, FLS, CRUD, and $User/$Profile/$Permission merge fields. NOT for Apex sharing keywords (see apex/with-without-sharing-and-context). NOT for record-access troubleshooting at the user level (see security/record-access-troubleshooting).

flow-migration-from-trigger

8
from PranavNagrecha/AwesomeSalesforceSkills

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).

flow-invocable-from-apex

8
from PranavNagrecha/AwesomeSalesforceSkills

Author @InvocableMethod Apex classes that Flow can call as Actions. Design the input / output variable contract, bulk semantics (one list in, one list out), null handling, and error surfacing. Also covers the inverse direction: calling a flow from Apex via Flow.Interview. NOT for general Apex authoring (use apex-service-selector-domain). NOT for REST-exposed Apex (use apex-rest-resource-patterns).

flow-apex-defined-types

8
from PranavNagrecha/AwesomeSalesforceSkills

Design and use Apex-Defined Types as Flow variables for structured non-sObject data (HTTP callout payloads, External Service responses, complex configuration). Trigger keywords: apex-defined type, flow variable, @AuraEnabled class, flow http callout response. Does NOT cover building HTTP Callout Actions themselves, External Services schema, or raw Apex invocable methods.

trigger-framework

8
from PranavNagrecha/AwesomeSalesforceSkills

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

8
from PranavNagrecha/AwesomeSalesforceSkills

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).

scheduled-apex-failure-detection-and-monitoring

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when nightly batch / scheduled Apex jobs are failing without anyone noticing — covers why uncaught exceptions in `execute()` go to the debug log instead of email, how to query `AsyncApexJob` for `Status`, `NumberOfErrors`, and `ExtendedStatus`, when to implement `Database.RaisesPlatformEvents` so the platform publishes `BatchApexErrorEvent` on uncaught failures, how to subscribe to that event with an Apex trigger and notify operators, and how to layer a custom watcher schedule on top so silent-failure modes (job that never started, scheduled class deleted, queue stuck on `Queued`) still surface. Triggers: 'nightly batch failed at 2am with no notification', 'how do we know if a scheduled apex job is failing', 'BatchApexErrorEvent vs custom retry logic', 'Setup Apex Jobs only shows last 7 days, where else can I look', 'job is stuck in queued status nobody noticed for a week'. NOT for general Apex exception handling patterns (use apex/apex-exception-handling-and-logging), NOT for Batch Apex authoring or chunking strategy (use apex/batch-apex-design), NOT for Setup → Apex Jobs UI walkthrough as an admin task (use admin/batch-job-scheduling-and-monitoring), NOT for retry logic itself (use apex/scheduled-apex-retry-patterns once authored).

recursive-trigger-prevention

8
from PranavNagrecha/AwesomeSalesforceSkills

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.