Every workflow declares at least one trigger in triggers: [...]. A trigger is how a run
starts.
| Builder | Signature | Starts a run via |
|---|---|---|
apiTrigger | apiTrigger(name, opts?) | flowctl run start --workflow <name> |
formTrigger | formTrigger(name, opts?) | submitting a trigger form |
webhookTrigger | webhookTrigger(name, opts?) | an inbound HTTP call |
scheduleTrigger | scheduleTrigger(name, { cron, collision?, timezone? }) | a cron schedule |
triggers: [
apiTrigger("create-order"),
scheduleTrigger("nightly", { cron: "0 9 * * *", collision: "skip", timezone: "UTC" }),
]
Scheduling with scheduleTrigger
cron— a 5-field standard cron expression (e.g."0 9 * * *"= 09:00 daily). The scheduler is minute-granular — no sub-minute schedules.collision— what to do when a prior scheduled run is still active:"skip"(default),"queue"(start after the prior finishes), or"parallel"(start anyway).timezone— an IANA name (e.g."America/New_York"); defaults to the engine’s local zone.
Keep the interval ≥ the run’s wall-clock duration. Under the default
skip, a fire that lands while the prior run is still active is skipped by design,
so a slow workflow runs less often than the cron implies.
A human-in-the-loop step makes the duration unbounded. A parked run stays
“active”, so under skip it blocks every later fire until someone responds. Decouple
the human leg (do the automated part and finish, hand off the HITL to a separate run), or use
collision: “parallel” / “queue”.
Add an apiTrigger alongside a schedule so you can start the workflow on demand
with flowctl run start while developing.
Validating start input
inputSchema on workflow({}) is a JSON Schema that validates the trigger --input at start
time. A start that fails validation is rejected before any step runs.
workflow({
name: "CreateOrder",
inputSchema: {
type: "object",
properties: { order_id: { type: "string" }, total: { type: "number" } },
required: ["order_id"],
},
initial: { order_id: null, total: 0 }, // --input is merged over this
triggers: [ apiTrigger("create-order") ],
steps: [ /* … */ ],
});
flowctl run start --workflow CreateOrder --input '{"order_id":"A-1","total":250}'
flowctl trigger schema api CreateOrder create-order -o json # fetch the expected input shape
The start --input is merged over initial, so anything omitted falls back to its initial
value.
Next: Errors, retries & recovery.