SfSkills Domains Docs GitHub

Home / flow / scheduled-flows

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 — use flow/flow-time-based-patterns. NOT for large-scale batch processing — use apex/batch-apex-patterns.

Open the skill folder on GitHub


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:

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:

PrimitiveWhen to useWhen NOT
Schedule-triggered flowPeriodic 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 flowRecord 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.scheduleHigh-volume periodic processing, complex joins, large record setsWhen 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.

Two Execution Modes: With Or Without An Object

The object in the Start element is optional, and that single choice changes the flow's entire execution model. Decide it before you draw anything else.

Object selected (+ criteria)No object selected
What runsThe platform queries matching records and creates one interview per recordA single interview, once per scheduled run
$RecordAvailable — the flow's logic operates on one recordNot available
BatchingInterviews run in batches (default 200, settable 1–200 in the Start element)N/A — one interview
Get + Loop over the same objectAnti-pattern — the platform already iterates for youCorrect and expected

Trailhead states it directly: "When the flow runs, it finds all of that object's records that match the criteria, and makes them available through $Record," and "If you don't set an object and criteria, $Record isn't available." Trailhead also notes $Record "actually refers to multiple records" — meaning it spans the whole matching set across interviews; within any single interview it resolves to exactly one record, which is why you author for one.

The consequence most builders miss: when an object is selected, you author the flow as if it handles exactly one record. Adding a Get Records + Loop over that same object re-fetches the whole set inside every interview — N interviews × N iterations instead of N. The record scope belongs in the Start element's criteria, not in a Loop.

Conversely, an object-less schedule-triggered flow is just a scheduled job. There is no $Record and nothing iterates for you, so Get Records + Loop (or Transform / Collection Filter / Collection Sort) is the correct shape — a loop at the top of this mode is not an anti-pattern.

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:

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:

PatternImplementationTradeoff
Processing flagProcessed_Today__c = true set at end of processing; reset nightlySimple; requires a reset job
Last-processed dateLast_Processed_At__c = <timestamp>; filter on Last_Processed_At__c < TODAYNo reset needed; field can stale
Status transitionMove record to a terminal status that the filter excludesCleanest; requires business-meaningful status
External lockWrite to a custom "job log" object; check before processingMost 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:

Common Patterns

Pattern 1: Narrow Nightly Follow-Up Flow

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

Structure (object-selected mode — the platform iterates, so author for ONE record):

Start: Daily at 2am
  Object: Case
  Criteria: Status = 'Pending' AND CreatedDate < TODAY - 7 AND Last_Reminded_Date__c != TODAY
Plan (runs once per matching record, $Record is that record):
  └── [Send Custom Notification OR Email Alert]  → addressed from $Record
  └── [Update Records: $Record.Last_Reminded_Date__c = TODAY]
  └── [Fault path: log + notify admin]

No Get Records. No Loop. The Start element's criteria are the record selection; adding a Get + Loop here would re-query every matching Case inside every interview.

Object-less variant: if you leave the object blank (say, to build a daily digest across several objects), the flow runs as one interview and you do need Get Records + Loop — plus an explicit LIMIT and a bulk Update after the loop, since nothing bounds the set for you.

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:

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:

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:

Decision Guidance

SituationRecommended ApproachReason
Recurring job scans a bounded set of records daily or weeklySchedule-triggered flow (Pattern 1)Good fit for predictable recurring automation
Follow-up tied to a specific record save eventScheduled path on record-triggered flowEvent-based, not portfolio-wide
Job volume or processing complexity highBatch Apex or async code boundaryFlow is not the best execution engine for heavy batch work
Repeated reminders need duplicate preventionAdd idempotent markers or date fieldsRecurring runs must know what's already processed
Selection criteria vague or unboundedRedesign before schedulingSchedule will amplify poor scope decisions
Job needs to run multiple times per dayConsider sub-hourly schedule (flow limits) or move to Batch ApexFlow scheduling granularity may not fit
Requires external callout per recordHTTP Action inline for small sets; async via Platform Events for largePer-record callouts exhaust callout limits

Review Checklist

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:

Output Artifacts

ArtifactDescription
Scheduling designRecommendation for schedule-triggered flow, scheduled path, or Apex
Scope and idempotency planRules for bounded selection and duplicate prevention
Volume review findingsRisks around record set size, side effects, execution model choice
Run-log specificationScheduled_Flow_Run__c schema + dashboard guidance

Package files