KEEP LEARNING
Build the bigger picture.
The Workflow Engineer connects individual n8n concepts to testing, deployment and running a complete workflow.
Tips > Reliability & Performance
When a workflow requires human approval (e.g., content review, expense approval, data verification), use the Wait node to pause execution until the human
When a workflow needs human approval, the Wait node pauses execution until the person responds -- typically through a resume URL behind Slack approve and reject buttons. Always set a timeout so the workflow does not hang when the approver is unavailable; on timeout it can escalate or take a default path. This adds human oversight without blocking a workflow indefinitely.
When a workflow requires human approval (e.g., content review, expense approval, data verification), use the Wait node to pause execution until the human responds. Always configure a timeout so the workflow does not hang indefinitely if the approver is unavailable.
Real-world example: A content publishing workflow generates an article with AI, then waits for editor approval before publishing. If no response comes within 48 hours, it escalates to the managing editor.
Workflow structure:
[Trigger] --> [AI: Generate Article] --> [Slack: Send for Review]
--> [Wait: 48h timeout] --> [IF: Approved?]
|
+--------+--------+
| |
[Approved] [Timeout/Rejected]
| |
[Publish] [Escalate to Manager]Wait node configuration:
{
"resume": "webhook",
"options": {
"webhookSuffix": "article-review",
"timeout": "48",
"timeoutUnit": "hours"
}
}The Slack message includes approval buttons that call back to the Wait node's resume URL:
// Code node: "Prepare Approval Request"
const article = $input.first().json;
const resumeUrl = $execution.resumeUrl;
return [{
json: {
slackMessage: {
channel: '#content-review',
text: `*New article for review*\n\nTitle: ${article.title}\nWord count: ${article.wordCount}\nGenerated by: ${article.model}`,
attachments: [
{
text: article.summary,
fallback: 'Article review request',
callback_id: 'article_review',
actions: [
{
type: 'button',
text: 'Approve',
style: 'primary',
url: `${resumeUrl}?approved=true`
},
{
type: 'button',
text: 'Reject',
style: 'danger',
url: `${resumeUrl}?approved=false&reason=needs_revision`
}
]
}
]
},
article
}
}];Handle the timeout case:
// Code node: "Handle Wait Result" (after the Wait node)
const waitResult = $input.first().json;
// Check if this was a timeout or a response
if (waitResult.$timedOut) {
return [{
json: {
status: 'timeout',
action: 'escalate',
message: 'No response received within 48 hours'
}
}];
}
return [{
json: {
status: waitResult.query?.approved === 'true' ? 'approved' : 'rejected',
reason: waitResult.query?.reason || null,
respondedAt: new Date().toISOString()
}
}];Warning: Wait node and execution data When a workflow resumes from a Wait node, n8n loads the execution data from the database. On self-hosted instances, make sure your database has enough storage and that execution data pruning does not delete waiting executions. Set EXECUTIONS_DATA_MAX_AGE higher than your longest Wait timeout.
This pattern enables human oversight without blocking indefinitely. The timeout ensures every workflow eventually reaches a terminal state.
Related: Use "Pin Data" to Freeze Node Output · Break Large Workflows into Sub-Workflows
KEEP LEARNING
The Workflow Engineer connects individual n8n concepts to testing, deployment and running a complete workflow.
APPLY IT TO YOUR SYSTEM
Bring the process, the tools involved and an example of where the current workflow gets stuck.