Workflow steps and context
Define named steps, read the runtime context and handle failures without implying automatic retries.
Steps
A step is an exported const built by defineStep. You call it from the run function, context first.
| Call | What happens |
|---|---|
defineStep(name, operation) | Names a unit of work. The operation receives the context, then the step's own arguments. An empty name throws. |
await readRate(ctx, …args) | Runs the operation through the runtime's step boundary, which records the invocation under that name. |
step.stepName | The name the step was declared with, readable on the returned function. |
WorkflowContext
The single argument your run function and every step receives.
| Member | Purpose |
|---|---|
ctx.input | The typed workflow input: the delivery's body on a webhook or event run. A scheduled run is handed none, so type it void. |
ctx.config.NAME | Non-sensitive workflow values the owner supplies. The names are fixed at build time from the ones your source spells out. |
ctx.secrets.NAME | The plaintext secrets the owner stored, named the same way. Never log one or return it in output. |
ctx.trigger | The trigger that started this run, on every run: its type and key, plus what that type delivers, in the table below. |
ctx.log(message, data?) | A human-readable annotation in the run timeline. Observational only — it never changes control flow. |
ctx.now() | Runtime-provided current time, in milliseconds. |
ctx.random() | Runtime-provided randomness. |
ctx.integrations | The integration ports. |
| ctx.trigger.type | Always carries | When known |
|---|---|---|
manual | key | nothing else |
schedule | key, cron, expectedAt | timeZone |
once | key, expectedAt | nothing else |
webhook | key, integration, deliveryId | eventType, signedAt |
event | key, integration, deliveryId, source | eventType, signedAt, acquisitionKind |
Errors
Throwing the right one is how you record whether the failure was worth waiting on. Nothing retries it for you.
| Class | Meaning |
|---|---|
RetryableError(message, { retryAfterMs?, code?, detail?, operation? }) | The failure is transient, and retryAfterMs records how long a caller should wait. It does not schedule a retry. |
NonRetryableError(message, { code?, detail?, operation? }) | The failure will not clear on its own. Use it for bad input, bad shapes, and permission failures. |
WorkflowError | The abstract base both extend, carrying retryable, code, detail and operation. |
Neither class causes a retry, and nothing replays a workflow: a failed step ends its run, and a step is a recorded boundary rather than a resume point. So make a step's work safe to repeat, express the waiting and the duplicate check you need in the workflow itself, and never report an outcome the provider did not confirm.
Related documentation
Start with the complete module example, choose workflow triggers, and review runtime limits and responsibilities.