<Approval> is the explicit approval-node counterpart to $.approval() in the Effect builder and kind: approval in TOON.
It pauses the workflow until a human approves or denies the node, then writes an ApprovalDecision row to the configured output table:
Import
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | (required) | Stable node id. Must be unique within the workflow. |
output | z.ZodObject | Table | string | (required) | Where to persist the ApprovalDecision output. Pass a Zod schema from outputs (recommended), a Drizzle table, or a string key. |
outputSchema | z.ZodObject | approvalDecisionSchema | Override the decision schema when using the manual DB API. |
request | { title: string; summary?: string; metadata?: Record<string, unknown> } | (required) | Human-facing approval request metadata. title becomes the node label; summary and metadata are stored in task metadata. |
onDeny | "fail" | "continue" | "skip" | "fail" | What happens after a denial. "continue" and "skip" still persist a denial decision object. |
dependsOn | string[] | undefined | Explicit dependency on other task node IDs. The approval will not run until all listed tasks complete. |
needs | Record<string, string> | undefined | Named dependencies on other tasks. Keys become context keys, values are task node IDs. |
skipIf | boolean | false | Skip the approval node entirely. |
timeoutMs | number | undefined | Maximum time in milliseconds to wait for an approval decision. The node fails if it exceeds this duration. |
retries | number | 0 | Number of retry attempts on failure before the node is marked as failed. |
retryPolicy | RetryPolicy | undefined | Retry timing configuration. { backoff?: "fixed" | "linear" | "exponential", initialDelayMs?: number }. Controls the delay between retry attempts. |
continueOnFail | boolean | false | When true, the workflow continues executing subsequent nodes even if this approval fails. |
cache | CachePolicy | undefined | Caching configuration. { by?: (ctx) => unknown, version?: string }. When provided, the engine can skip re-execution if a cached result with the same key and version exists. |
label | string | request.title | Optional display label override. |
meta | Record<string, unknown> | undefined | Additional metadata merged with request.summary / request.metadata. |
Schema-driven Example
Manual API Example
When you use the lower-level manual JSX API, passoutputSchema={approvalDecisionSchema} if your output prop is a Drizzle table instead of a schema key.
Behavior
- The workflow enters
waiting-approvalwhen the node is reached. smithers approveorsmithers denyupdates the approval record durably.- On resume, the node resolves to a decision object and downstream JSX can branch on that value.
onDeny="fail"behaves like a hard gate.onDeny="continue"lets you branch explicitly ondecision.approved.
When to Use <Approval> vs needsApproval
Use <Approval> when the approval is a real workflow node whose decision should be persisted as data and reused by downstream logic.
Use needsApproval on <Task> when you only need a simple pause before the task runs and you do not need a separate decision value in the graph.