- Docs
- Cron, Retries & Flows
- Flow Producer
- Reference
Every method, spelled out.
The producer surface, what a processor can ask about its children mid-run, and the full field list of a step so you can build graphs programmatically.
Reference
Section titled “Reference”FlowProducer methods
Section titled “FlowProducer methods”| Method | Description |
|---|---|
add(flow, opts?) | BullMQ v5: tree where children complete before the parent (atomic) |
addBulk(flows[]) | BullMQ v5: add multiple flow trees (atomic, all-or-nothing) |
getFlow({ id, queueName, depth?, maxChildren? }) | Retrieve a flow tree by root job ID |
addChain(steps[]) | Sequential execution: A → B → C |
addBulkThen(parallel[], final) | Parallel then converge: [A, B, C] → D |
addTree(root) | Hierarchical tree with nested children |
getParentResult(parentId) | Exact result of one completed parent, embedded or TCP |
getParentResults(parentIds[]) | Ordered results for completed parents, embedded or TCP |
close() / disconnect() | Close the connection pool |
waitUntilReady() | Wait until the FlowProducer is connected |
The table describes the Bun package. The TypeScript SDK (bunqueue-client) exports the same FlowProducer class, so every method above, closing included, works there too. In the other SDKs: add and addChain exist in all of them; getFlow in Python, PHP and Go (as getFlow(jobId, depth), without queueName/maxChildren); addBulk and addBulkThen in Python; addTree, getParentResult and getParentResults in none.
FlowProducer extends Node.js EventEmitter (BullMQ v5 compatible). Its
closing property is null while live, then becomes the stable Promise returned
by the first close() or disconnect() call. Repeated shutdown calls return
that same Promise, including if teardown fails.
The result helpers stay synchronous in embedded mode for compatibility and
return Promises in TCP mode. Always await them in portable code. They preserve
0, false, an empty string, and persisted null; an ID with no stored result
is omitted from the map (or resolves to undefined for the single read).
The behavior described in this guide is exercised against a real broker, in both
embedded and TCP mode, by test/docs-flow-guide/ (one suite per page) and
test/flow-docs-examples.test.ts (the Quick Start, chain, fan-in, parent-first
tree, per-queue defaults, bounded traversal, and both failure-value APIs). The
external-SDK tabs are not executed by these suites.
Job methods inside a worker processor
Section titled “Job methods inside a worker processor”| Method | Description |
|---|---|
job.getChildrenValues() | Results of all completed children |
job.getFailedChildrenValues() | Errors from children that failed with continueParentOnFailure |
job.getIgnoredChildrenFailures() | Errors from children that failed with ignoreDependencyOnFailure |
job.removeChildDependency() | Atomically detach this job from its parent; promotes the parent if it was the last pending child |
job.removeUnprocessedChildren() | Cancel every direct child that is still queued (waiting, delayed, prioritized, or waiting for its own children); active and finished children, and grandchildren, are unaffected |
In the TypeScript SDK all five are job methods, exactly as in the Bun package (Queue.getChildrenValues(id) also exists). In Python, get_children_values is on the job and on Queue; the other four are on Queue, taking the job id. PHP and Go have only getChildrenValues on Queue; Rust and Elixir have none of them yet.
Step shape
Section titled “Step shape”// addChain / addBulkThen / addTreeinterface FlowStep<T = unknown> { name: string; // Job name queueName: string; // Target queue data: T; // Job data opts?: JobOptions; // Optional job options children?: FlowStep<T>[]; // Child steps (addTree)}
// flow.add / flow.addBulk (children run BEFORE the parent)interface FlowJob<T = unknown> { name: string; queueName: string; data?: T; opts?: JobOptions; children?: FlowJob<T>[];}// addChain / addBulkThen / addTreeinterface FlowStep<T = unknown> { name: string; // Job name queueName: string; // Target queue data: T; // Job data opts?: JobOptions; // Optional job options children?: FlowStep<T>[]; // Child steps (addTree)}
// flow.add / flow.addBulk (children run BEFORE the parent)interface FlowJob<T = unknown> { name: string; queueName: string; data?: T; opts?: JobOptions; children?: FlowJob<T>[];}# add_chain / add_bulk_then steps and add / add_bulk nodes are plain dicts:step = {"name": "...", "queueName": "...", "data": {}, "opts": {}}node = {"name": "...", "queueName": "...", "data": {}, "opts": {}, "children": []} # children run BEFORE the parent// addChain steps and add() nodes are plain arrays:$step = ['name' => '...', 'queueName' => '...', 'data' => [], 'opts' => []];$node = ['name' => '...', 'queueName' => '...', 'data' => [], 'opts' => [], 'children' => []]; // children run BEFORE the parent// AddChaintype ChainStep struct { Name string QueueName string Data map[string]any Opts JobOptions}
// Add (children run BEFORE the parent)type FlowJob struct { Name string QueueName string Data map[string]any Opts JobOptions Children []FlowJob}// add_chainpub struct ChainStep { pub name: String, pub queue_name: String, pub data: Value, pub options: JobOptions,}
// add (children run BEFORE the parent)pub struct FlowJob { pub name: String, pub queue_name: String, pub data: Value, pub options: JobOptions, pub children: Vec<FlowJob>,}# add_chain steps and add/2 nodes are plain maps (note the :queue key):step = %{name: "...", queue: "...", data: %{}, options: []}node = %{name: "...", queue: "...", data: %{}, options: [], children: []} # children run BEFORE the parentflow.add() returns a JobNode: { job, children? }, recursively.
Where to go next
Section titled “Where to go next”| Flow Producer | Your first parent/child graph, and what is guaranteed |
| Flow Patterns | Chains, fan-in, trees, reading child results, options |
| Flow Failure Handling | What a parent does when a child dies for good |