scheduled-flows

Use when designing or reviewing schedule-triggered flows for recurring automation, replacement of time-based workflow patterns, bounded record selection, idempotent processing, and escalation to Apex when volume is too high. Triggers: 'scheduled flow design', 'nightly flow job', 'time based workflow replacement', 'schedule triggered flow limits'. NOT for record-triggered scheduled paths or large-scale batch processing that should be built directly in Batch Apex.

Best use case

scheduled-flows is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use when designing or reviewing schedule-triggered flows for recurring automation, replacement of time-based workflow patterns, bounded record selection, idempotent processing, and escalation to Apex when volume is too high. Triggers: 'scheduled flow design', 'nightly flow job', 'time based workflow replacement', 'schedule triggered flow limits'. NOT for record-triggered scheduled paths or large-scale batch processing that should be built directly in Batch Apex.

Teams using scheduled-flows 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/scheduled-flows/SKILL.md --create-dirs "https://raw.githubusercontent.com/PranavNagrecha/AwesomeSalesforceSkills/main/skills/flow/scheduled-flows/SKILL.md"

Manual Installation

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

How scheduled-flows Compares

Feature / Agentscheduled-flowsStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use when designing or reviewing schedule-triggered flows for recurring automation, replacement of time-based workflow patterns, bounded record selection, idempotent processing, and escalation to Apex when volume is too high. Triggers: 'scheduled flow design', 'nightly flow job', 'time based workflow replacement', 'schedule triggered flow limits'. NOT for record-triggered scheduled paths or large-scale batch processing that should be built directly in Batch Apex.

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 automation needs to run on a recurring cadence rather than directly from a record event. Schedule-triggered flows work well for bounded recurring tasks such as reminders, renewals, or cleanup logic. They become risky when teams treat them like a general-purpose batch engine and let the record scope or side effects grow without discipline.

The three most common failure modes of scheduled flows in production: (1) unbounded start filter that touches half the org's records on every run, (2) missing idempotency so the same records get "reminded" on every nightly run, (3) silent failure because nobody is monitoring the schedule-trigger error queue. This skill exists to prevent all three — and to know when to stop and use Batch Apex instead.

## Before Starting

Check for `salesforce-context.md` in the project root. If present, read it first.

Gather if not available:
- What recurrence is required, and is the automation tied to a business calendar or to a record event that might fit a scheduled path better?
- How many records could match the criteria on a normal day, and what is the worst-case volume during seasonal or data-load spikes?
- How will the flow avoid duplicate work if it runs again, partially fails, or overlaps with another automation?
- What is the expected runtime budget (each scheduled-flow invocation must finish within async limits)?
- Who owns the error-email recipient for this schedule? What's the SLA on response?

## Core Concepts

The core design problem in scheduled flows is not the schedule itself. It is **bounded scope** plus **repeat-safe behavior**. A recurring automation that cannot explain which records it will touch, why it will touch them only once when appropriate, and when it should escalate out of Flow is not ready for production.

### Choose The Right Time Primitive

Three options; only one is a schedule-triggered flow:

| Primitive | When to use | When NOT |
|---|---|---|
| **Schedule-triggered flow** | Periodic scan of records matching time-based criteria independently of save events (nightly lease-renewal reminders, quarterly data cleanup) | When triggered from a record event — use scheduled path instead |
| **Scheduled Path on record-triggered flow** | Record event → wait N days → do work (send follow-up email 14d after Case created) | When there's no triggering record — schedule-triggered is the answer |
| **Batch Apex scheduled via System.schedule** | High-volume periodic processing, complex joins, large record sets | When the workload truly fits Flow's model (small set, simple operations, admin-maintainable) |

A wrong primitive choice is the most common scheduled-flow design error. If the requirement starts "when a record is X and Y days old", it's likely a scheduled path, not a schedule-triggered flow.

### Bounded Selection Comes First

The start criteria should narrow the job to a realistic set of records. Wide-open scans with complex branching downstream create both performance risk and support ambiguity. Good scheduled flows have clear filters, explicit stop conditions, and a manageable result set per run (< 250 records per run is a good rule of thumb for pure-Flow execution).

Concrete selection criteria should combine:
- **Type/status filter** — `Status = 'Open' AND RecordType = 'Support'`.
- **Time-window filter** — `LastModifiedDate < TODAY - 30` or `CreatedDate = THIS_MONTH`.
- **Processing marker** — `Last_Reminded_Date__c != TODAY` (see idempotency below).

Filters that rely on computed fields or formula predicates WILL slow the scheduled query. Prefer indexed fields + date ranges + processing flags.

### Idempotency Matters In Recurring Automation

A recurring flow should be able to answer: "has this record already been processed for this job window?" Without idempotency, the same records get reminded, updated, or emailed every run — a frequent source of "the system spammed our customers" incidents.

Idempotency patterns:

| Pattern | Implementation | Tradeoff |
|---|---|---|
| Processing flag | `Processed_Today__c = true` set at end of processing; reset nightly | Simple; requires a reset job |
| Last-processed date | `Last_Processed_At__c = <timestamp>`; filter on `Last_Processed_At__c < TODAY` | No reset needed; field can stale |
| Status transition | Move record to a terminal status that the filter excludes | Cleanest; requires business-meaningful status |
| External lock | Write to a custom "job log" object; check before processing | Most robust; highest overhead |

### Flow Is Not Always The Final Execution Engine

When the recurring job becomes large (> 500 records per run), computationally heavy (complex joins or multi-step transformations), or deeply iterative (nested loops with DML), the right answer may be to use the scheduled flow only as a lightweight orchestration layer or move the workload into Batch Apex entirely. The schedule does not justify using the wrong execution model.

**Signals Flow is no longer the right engine:**
- Record count per run > 500.
- CPU time approaches the async limit (60s sync / still constrained async).
- The Flow has > 5 DML operations in a loop.
- The job needs to run more than daily to stay current.
- Apex invocables are doing most of the real work (then just make it Batch Apex).

## Common Patterns

### Pattern 1: Narrow Nightly Follow-Up Flow

**When to use:** Recurring reminder or status update on a bounded slice of records.

**Structure:**
```text
Schedule: Daily at 2am
Entry criteria: Status = 'Pending' AND CreatedDate < TODAY - 7 AND Last_Reminded_Date__c != TODAY
Plan:
  └── [Get Records matching entry criteria, LIMIT 200]
  └── [Loop]:
       └── [Send Custom Notification OR Email Alert]
       └── [Assignment: Last_Reminded_Date__c = TODAY]
  └── [Update Records] (bulk update after loop)
  └── [Fault path: log + notify admin]
```

**Why not the alternative:** A broad nightly sweep without clear selection becomes unpredictable and expensive.

### Pattern 2: Scheduled Flow As Lightweight Orchestrator

**When to use:** The timing belongs in Flow, but the heavy work belongs elsewhere.

**Structure:**
```text
Schedule: Weekly on Monday 3am
Plan:
  └── [Get Records: this week's candidates (narrow filter)]
  └── [Decision: record_count > threshold?]
       └── Yes → [Invocable Apex: kick off Batch Apex job with candidate IDs]
       └── No  → [Process inline via Loop + subflow]
```

Flow owns the timing and the "is this worth running today" check. Apex owns the work.

### Pattern 3: Replace Time-Based Workflow With Explicit Criteria

**When to use:** Legacy time-based Workflow Rule being migrated to Flow.

**Structure:** The Workflow Rule's "Evaluate every time a record is created or edited" + time-based action becomes a record-triggered flow's Scheduled Path (NOT a schedule-triggered flow) — because the behavior is record-event-driven, not portfolio-scan-driven.

For ACTUAL portfolio-scan automation being migrated from custom Apex scheduled jobs: evaluate whether it's really Flow-shaped first. Many scheduled Apex jobs exist because there was no good Flow primitive; now that scheduled flows + scheduled paths exist, some can migrate, but not all.

### Pattern 4: Run Log + Monitoring

**When to use:** Any production scheduled flow — this is not optional.

**Structure:**
```text
Start of run → [Create Records: Scheduled_Flow_Run__c with start_time + run_id]
... main work ...
End of run → [Update Records: the same log record with end_time + record_count + status]
Fault path → [Update Records: log record with status='failed' + fault_message]
```

A Scheduled_Flow_Run__c object (or equivalent) gives operations:
- **Run history** — did the 3am job actually run last night?
- **Duration trends** — is the nightly job taking longer over time?
- **Failure visibility** — alert when `status='failed'` appears without alerting on every successful run.

## Decision Guidance

| Situation | Recommended Approach | Reason |
|---|---|---|
| Recurring job scans a bounded set of records daily or weekly | Schedule-triggered flow (Pattern 1) | Good fit for predictable recurring automation |
| Follow-up tied to a specific record save event | Scheduled path on record-triggered flow | Event-based, not portfolio-wide |
| Job volume or processing complexity high | Batch Apex or async code boundary | Flow is not the best execution engine for heavy batch work |
| Repeated reminders need duplicate prevention | Add idempotent markers or date fields | Recurring runs must know what's already processed |
| Selection criteria vague or unbounded | Redesign before scheduling | Schedule will amplify poor scope decisions |
| Job needs to run multiple times per day | Consider sub-hourly schedule (flow limits) or move to Batch Apex | Flow scheduling granularity may not fit |
| Requires external callout per record | HTTP Action inline for small sets; async via Platform Events for large | Per-record callouts exhaust callout limits |

## Review Checklist

- [ ] Schedule primitive is correct (scheduled flow vs scheduled path vs Batch Apex).
- [ ] Start criteria narrow the candidate record set intentionally (no bare `Active=true`).
- [ ] Idempotent markers prevent duplicate tasks, emails, or updates across runs.
- [ ] Failure handling exists for every DML element (Pattern A from `flow/fault-handling`).
- [ ] Volume expectations were reviewed for normal and worst-case runs.
- [ ] Heavy work was escalated out of Flow when appropriate.
- [ ] Run log exists (custom object or equivalent) for operational monitoring.
- [ ] Error-email recipient is a monitored mailbox, not a single inactive admin.

## 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 Common Patterns above
4. Validate — run the skill's checker script and verify against the Review Checklist above
5. Document — record any deviations from standard patterns and update the template if needed

---

## Salesforce-Specific Gotchas

1. **A recurring schedule amplifies weak selection logic** — broad filters turn into repeated large jobs quickly.
2. **Recurring automation needs duplicate prevention explicitly** — without markers, the same records can be processed on every run.
3. **Scheduled flows are not a substitute for true batch architecture** — the timing may fit, while the execution model does not.
4. **A record-event requirement may fit scheduled paths better** — choosing the wrong time primitive creates unnecessary complexity.
5. **Scheduled-flow errors email the Process Automation user**, same as record-triggered flows. Verify the recipient is monitored annually.
6. **Scheduled flows DO NOT retry automatically on failure** — a failed run just... doesn't run. The next scheduled run tries fresh. Build retry logic into the flow if the business needs it.
7. **Two schedules overlapping can compete for records** — if two scheduled flows both filter "Status = Open", run one, the records transition, then the second flow sees different results than the first. Design mutually-exclusive filters or serialize schedules.
8. **Salesforce limits the number of scheduled jobs per org** — check `AsyncApexJob` + scheduled-flow limits before adding the Nth schedule.
9. **Daily-at-2am is everyone's default** — so everyone's org hits Salesforce's scheduler peak load at 2am. Spread actual scheduled times to avoid platform contention.
10. **Scheduled flows can't be paused mid-run** — once started, they run to completion or failure. Design the scope accordingly.

## Proactive Triggers

Surface these WITHOUT being asked:

- **Scheduled flow with no idempotency marker** → Flag as Critical. Will double-process on retry or next run.
- **Scheduled flow with unbounded start criteria (e.g. "Active = true" alone)** → Flag as Critical. Volume bomb waiting to happen.
- **Record-event requirement being built as scheduled flow instead of scheduled path** → Flag as High. Wrong primitive.
- **Scheduled flow > 500 records per run with no escalation plan** → Flag as High. Probably needs Batch Apex.
- **No run log / monitoring surface for production scheduled flow** → Flag as High. Silent failure invitation.
- **Multiple scheduled flows on same object with overlapping filters** → Flag as Medium. Coordination risk.
- **Scheduled flow error email recipient is inactive** → Flag as Critical. Unseen failure pattern.
- **All scheduled flows set for 2am** → Flag as Low. Platform-peer peak-load contention; spread schedules.

## Output Artifacts

| Artifact | Description |
|---|---|
| Scheduling design | Recommendation for schedule-triggered flow, scheduled path, or Apex |
| Scope and idempotency plan | Rules for bounded selection and duplicate prevention |
| Volume review findings | Risks around record set size, side effects, execution model choice |
| Run-log specification | Scheduled_Flow_Run__c schema + dashboard guidance |

## Related Skills

- **flow/flow-bulkification** — use when the recurring job may still break under shared limit pressure.
- **flow/fault-handling** — use when the main challenge is how background failures should be surfaced.
- **flow/record-triggered-flow-patterns** — use when a scheduled path on a record-triggered flow is the right primitive instead.
- **apex/batch-apex-patterns** — use when the workload has clearly crossed into true batch-processing territory.
- **standards/decision-trees/async-selection.md** — upstream decision tree for scheduled flow vs Batch Apex vs Queueable.

Related Skills

scheduled-erp-sync-pattern

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when designing a recurring (15-minute / hourly / nightly) data exchange between Salesforce and an external ERP system (Oracle EBS, SAP, NetSuite, Workday, Dynamics, etc.) where Salesforce is the *initiator* and pulls or pushes deltas on a schedule. Covers the full pattern: scheduled Apex → Queueable callout chain → REST request to ERP → upsert into a staging custom object → downstream reconciliation; plus watermark management (timestamp / cursor / full-refresh modes), idempotency via External ID, retry with exponential backoff, dead-letter custom object, and the volume thresholds that should redirect you to Bulk API 2.0, Change Data Capture, or MuleSoft. Triggers: 'integration to oracle erp every 15 minutes', 'scheduled sync pattern enterprise erp', 'pull netsuite invoices into salesforce nightly', 'apex schedulable callout to sap', 'how do i sync salesforce contacts to workday hourly', 'design a polling integration to my erp'. NOT for one-shot ETL imports (use data/data-loader-bulk-api), NOT for real-time inbound from ERP via Platform Events / Pub-Sub API (use integration/platform-events-publish-subscribe), NOT for outbound *event-driven* push (use integration/change-data-capture-consumer-pattern), NOT for MuleSoft / iPaaS architecture decisions (use architect/mulesoft-vs-native-integration-decision). When the data volume routinely exceeds 10K records per cycle or sub-minute latency is required, explicitly route to the Streaming / CDC / iPaaS skills instead.

oauth-flows-and-connected-apps

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when choosing or reviewing Salesforce OAuth flows and connected-app policy for integrations, including client credentials, JWT bearer, authorization code, device flow, scopes, and token lifecycle controls. Triggers: 'OAuth flow', 'connected app', 'client credentials', 'JWT bearer', 'refresh token', 'integration user'. NOT for record-level sharing design or for simple Named Credential usage when the auth-flow decision is already settled.

subflows-and-reusability

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when extracting reusable Flow logic into subflows, defining input and output variables, keeping parent flows maintainable, and sharing common automation contracts across multiple flows. Triggers: 'reuse this flow logic', 'how should subflow variables work', 'too much duplicated flow logic', 'subflow contract design'. NOT for Apex-called Flow execution direction or Flow Orchestration process design.

screen-flows

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when designing or reviewing interactive Flow screen experiences, including navigation, validation, screen component choice, custom LWC screen components, and user-safe commit timing. Triggers: 'screen flow validation', 'back button behavior in flow', 'custom flow screen component', 'screen flow UX'. NOT for Experience Cloud guest exposure or custom property editor design-time tooling.

scheduled-flow-not-running-debug

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when a Schedule-Triggered Flow is configured but is not firing at the expected time, or appears active in Setup → Flows but never produces output. Covers where scheduled flows actually surface (Setup → Scheduled Jobs, NOT Setup → Apex Jobs), the AsyncApexJob / CronTrigger evidence trail, top causes (deactivated scheduling user, daylight-savings transitions, time-zone mismatches between scheduling user and org, fault-paths that quietly stop the schedule, daily async-Apex limit pressure), and recovery steps (re-schedule via Apex, run the flow manually with the same input, switch the scheduling user). Triggers: 'how do I schedule a flow to run every monday', 'scheduled flow not firing', 'flow scheduled but no execution', 'scheduled flow stopped working last week', 'monday 6am scheduled flow did not run after dst change'. NOT for designing a new scheduled flow's record scope or idempotency (use flow/scheduled-flows), NOT for record-triggered Scheduled Paths that don't fire (use flow/flow-time-based-patterns), NOT for general Batch Apex job monitoring (use admin/batch-job-scheduling-and-monitoring).

orchestration-flows

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when designing or reviewing Flow Orchestration for long-running, multi-user, or asynchronous business processes with stages, steps, work items, and monitoring needs. Triggers: 'flow orchestration', 'work item', 'stages and steps', 'multi-user process', 'long-running flow'. NOT for simple single-transaction record-triggered flows or lightweight approval routing that does not need orchestration.

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

apex-scheduled-jobs

8
from PranavNagrecha/AwesomeSalesforceSkills

Scheduling Apex classes using the Schedulable interface: implementing execute(), cron expressions, System.schedule(), monitoring CronTrigger records, job limits, and job chaining patterns. NOT for Batch Apex scheduling (use batch-apex-patterns) or Flow scheduled paths.

scheduled-path-patterns

8
from PranavNagrecha/AwesomeSalesforceSkills

Scheduled Paths in record-triggered Flow: delayed execution, time-offset from field, batch size tuning, monitoring Paused Flow Interviews, async limits. NOT for Scheduled Flow (use scheduled-flow-patterns). NOT for time-based workflow rules (use migrate-workflow-pb).

cpq-approval-workflows

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when configuring or troubleshooting Salesforce CPQ Advanced Approvals: setting up SBAA__ApprovalRule__c, SBAA__ApprovalVariable__c for cross-line aggregation, SBAA__ApprovalChain__c for ordered approver sequences, escalation timeouts, Smart Approvals for re-quote skip logic, and permission set assignment for the Advanced Approvals managed package. Trigger keywords: CPQ Advanced Approvals, SBAA approval rule, approval variable, approval chain, discount approval, line-level approval, Smart Approvals, requote approval. NOT for standard Salesforce approval processes (use the approval-processes skill), CPQ pricing configuration (use cpq-pricing-rules), or quote template setup.

xss-and-injection-prevention

8
from PranavNagrecha/AwesomeSalesforceSkills

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

visualforce-security-and-modernization

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when hardening or modernizing legacy Visualforce pages — covers the platform CSRF token model and when disabling it is a security regression, view state encryption guarantees and the 170 KB ceiling, FLS/CRUD enforcement gaps on `<apex:outputField>` and on getters that return sObjects, `<apex:includeScript>` interaction with the org Content Security Policy, hosting LWC inside a VF page via `lightning:container` / `lightning-out`, and the retire-vs-harden-vs-leave-alone decision for an inventory of legacy pages. Triggers: 'should I rewrite this Visualforce page in LWC', 'CSRF protection disabled on Visualforce page is that safe', 'community user sees a field they should not on a Visualforce page', 'view state encryption is that enough for sensitive data', 'how do I host an LWC inside a Visualforce page', 'apex:dynamicComponent and apex:actionFunction safe to keep'. NOT for greenfield Visualforce architecture (use apex/visualforce-fundamentals — controller types, view state pattern selection, PDF rendering); NOT for Visualforce email template authoring (use apex/visualforce-email-templates if/when that skill is authored); NOT for general Apex security review across triggers and async (use apex/soql-security and security/secure-coding-review-checklist).