Suspend & Resume Workflows
Trust: ★★★☆☆ (0.90) · 0 validations · developer_reference
Published: 2026-05-10 · Source: crawler_authoritative
Tình huống
Mastra documentation explaining how to pause workflow execution at any step and resume it later, targeting developers building workflows that require human input, API callbacks, or throttled operations.
Insight
Workflows in Mastra can be paused at any step using suspend() to collect additional data, wait for API callbacks, throttle costly operations, or request human-in-the-loop input. When suspended, the current execution state is saved as a snapshot and persisted in the configured storage provider. The suspend() function returns a special value when a condition isn’t met, pausing workflow execution. The condition is checked against resumeData passed during resume. A step can define three schemas: inputSchema for initial input, resumeSchema for data passed on resume, and suspendSchema for context data accessible via suspendData when the step resumes. The suspendData parameter is automatically populated with the exact data passed to suspend() during the original suspension, allowing the resumed step to maintain context about why it was paused. Workflow status can be ‘suspended’ or ‘waiting’ (the latter from sleep methods). The suspended array on the result contains IDs of paused steps and nested workflows. Recovery of suspended runs uses workflow.getWorkflowRunById() with createWorkflowStateReader() from @mastra/core/workflows, which exposes suspended steps, resume labels, step payloads, and outputs without reading raw snapshot shapes.
Hành động
To pause a workflow, call suspend() within a step’s execute function when a condition isn’t met. The step must define a resumeSchema. Example: return await suspend({}) if !approved. To resume, call run.resume({ step: step1, resumeData: { approved: true } }) passing the step object for type-safety or a step ID string for flexibility. If only one step is suspended, omit the step argument to resume the last suspended step. Pass runId to createRun() when resuming with a runId: const run = await workflow.createRun({ runId: '123' }). Resume can be called from HTTP endpoints, event handlers, timers, or in response to human input. The suspendData parameter in the execute function receives the original data passed to suspend() when the step is resumed. To check if a workflow is suspended, inspect result.status === 'suspended' and access result.suspended[0] for the step ID. For recovery, use workflow.getWorkflowRunById('run-123') then createWorkflowStateReader(state) to access getSuspendedStep() and getResumeLabel(). Sleep methods (.sleep() and .sleepUntil()) pause at the workflow level with status ‘waiting’, unlike suspend() which sets status ‘suspended’.
Kết quả
Workflow execution pauses at the specified step with state saved as a snapshot. On resume with valid resumeData satisfying the suspend condition, execution continues from the paused step with the original suspend data available via suspendData. Snapshots persist across deployments and restarts. The workflow status reflects ‘suspended’ during pause and ‘waiting’ when using sleep methods.
Nội dung gốc (Original)
Suspend & resume
Workflows can be paused at any step to collect additional data, wait for API callbacks, throttle costly operations, or request human-in-the-loop input. When a workflow is suspended, its current execution state is saved as a snapshot. You can later resume the workflow from a specific step ID, restoring the exact state captured in that snapshot. Snapshots are stored in your configured storage provider and persist across deployments and application restarts.
Pausing a workflow with suspend()
Use suspend() to pause workflow execution at a specific step. You can define a suspend condition in the step’s execute block using values from resumeData.
- If the condition isn’t met, the workflow pauses and returns
suspend(). - If the condition is met, the workflow continues with the remaining logic in the step.

const step1 = createStep({
id: 'step-1',
inputSchema: z.object({
userEmail: z.string(),
}),
outputSchema: z.object({
output: z.string(),
}),
resumeSchema: z.object({
approved: z.boolean(),
}),
execute: async ({ inputData, resumeData, suspend }) => {
const { userEmail } = inputData
const { approved } = resumeData ?? {}
if (!approved) {
return await suspend({})
}
return {
output: `Email sent to ${userEmail}`,
}
},
})
export const testWorkflow = createWorkflow({
id: 'test-workflow',
inputSchema: z.object({
userEmail: z.string(),
}),
outputSchema: z.object({
output: z.string(),
}),
})
.then(step1)
.commit()Restarting a workflow with resume()
Use resume() to restart a suspended workflow from the step where it paused. Pass resumeData matching the step’s resumeSchema to satisfy the suspend condition and continue execution.

import { step1 } from './workflows/test-workflow'
const workflow = mastra.getWorkflow('testWorkflow')
const run = await workflow.createRun()
await run.start({
inputData: {
userEmail: '[email protected]',
},
})
const handleResume = async () => {
const result = await run.resume({
step: step1,
resumeData: { approved: true },
})
}Passing the step object provides full type-safety for resumeData. Alternatively, you can pass a step ID for more flexibility when the ID comes from user input or a database.
const result = await run.resume({
step: 'step-1',
resumeData: { approved: true },
})If only one step is suspended, you can omit the step argument entirely and Mastra will resume the last suspended step in the workflow.
When resuming with only a runId, create a run instance first using createRun().
const workflow = mastra.getWorkflow('testWorkflow')
const run = await workflow.createRun({ runId: '123' })
const stream = run.resume({
resumeData: { approved: true },
})You can call resume() from anywhere in your application, including HTTP endpoints, event handlers, in response to human input, or timers.
const midnight = new Date()
midnight.setUTCHours(24, 0, 0, 0)
setTimeout(async () => {
await run.resume({
step: 'step-1',
resumeData: { approved: true },
})
}, midnight.getTime() - Date.now())Accessing suspend data with suspendData
When a step is suspended, you may want to access the data that was provided to suspend() when the step is later resumed. Use the suspendData parameter in your step’s execute function to access this data.
const approvalStep = createStep({
id: 'user-approval',
inputSchema: z.object({
requestId: z.string(),
}),
resumeSchema: z.object({
approved: z.boolean(),
}),
suspendSchema: z.object({
reason: z.string(),
requestDetails: z.string(),
}),
outputSchema: z.object({
result: z.string(),
}),
execute: async ({ inputData, resumeData, suspend, suspendData }) => {
const { requestId } = inputData
const { approved } = resumeData ?? {}
// On first execution, suspend with context
if (!approved) {
return await suspend({
reason: 'User approval required',
requestDetails: `Request ${requestId} pending review`,
})
}
// On resume, access the original suspend data
const suspendReason = suspendData?.reason || 'Unknown'
const details = suspendData?.requestDetails || 'No details'
return {
result: `${details} - ${suspendReason} - Decision: ${approved ? 'Approved' : 'Rejected'}`,
}
},
})The suspendData parameter is automatically populated when a step is resumed and contains the exact data that was passed to the suspend() function during the original suspension. This allows you to maintain context about why the workflow was suspended and use that information during the resume process.
Identifying suspended executions
When a workflow is suspended, it restarts from the step where it paused. You can check the workflow’s status to confirm it’s suspended, and use suspended to identify the paused step or nested workflow.
const workflow = mastra.getWorkflow('testWorkflow')
const run = await workflow.createRun()
const result = await run.start({
inputData: {
userEmail: '[email protected]',
},
})
if (result.status === 'suspended') {
console.log(result.suspended[0])
await run.resume({
step: result.suspended[0],
resumeData: { approved: true },
})
}Example output
The suspended array contains the IDs of any suspended workflows and steps from the run. These can be passed to the step parameter when calling resume() to target and resume the suspended execution path.
['nested-workflow', 'step-1']Recovering suspended runs
Use workflow.getWorkflowRunById() with createWorkflowStateReader() when your application needs to recover a suspended run from storage. The reader exposes suspended steps, resume labels, step payloads, and step outputs without reading the raw snapshot shape.
import { createWorkflowStateReader } from '@mastra/core/workflows'
const workflow = mastra.getWorkflow('testWorkflow')
const state = await workflow.getWorkflowRunById('run-123')
if (state?.status === 'suspended') {
const reader = createWorkflowStateReader(state)
const suspendedStep = reader.getSuspendedStep()
const approvalLabel = reader.getResumeLabel('approve')
const run = await workflow.createRun({ runId: state.runId })
await run.resume({
step: approvalLabel?.stepId ?? suspendedStep?.path,
resumeData: { approved: true },
forEachIndex: approvalLabel?.foreachIndex,
})
}For nested workflows, suspendedStep.path contains the resume path. For foreach suspensions, matching resume labels include foreachIndex when the label points to a specific iteration.
Sleep
Sleep methods can be used to pause execution at the workflow level, which sets the status to waiting. By comparison, suspend() pauses execution within a specific step and sets the status to suspended.
Available methods:
.sleep(): Pause for a specified number of milliseconds.sleepUntil(): Pause until a specific date
Related
Liên kết
- Nền tảng: Dev Framework · Mastra
- Nguồn: https://mastra.ai/docs/workflows/suspend-and-resume
Xem thêm: