The short answer: a variable only crosses the boundary if the subflow’s variable has Available for input or Available for output ticked, and the parent only sees those checkboxes on the active version of the subflow. That second part is why a variable you just created refuses to appear in the Subflow element. Activate the subflow, reopen the parent, and it is there.
The two checkboxes are a contract, not a convenience
Every variable in a flow has an availability setting. Input means the caller can push a value in before the subflow starts. Output means the caller can read the value out after it finishes. You can tick both, one, or neither, and neither is the default.
Tick only what you need. A variable marked for input and output on both sides is an invitation for the next person to write to it from the parent and wonder why the subflow overwrote them. Naming helps too: varAccountIdIn and varErrorMessageOut tell a reader the direction without opening the variable’s properties.
Constants, formulas, and choices cannot be passed. Only variables carry the availability flags, so if you need a formula result in the subflow, assign it to a variable first.
Why your new variable is not in the parent’s list
Four causes, in the order they actually happen:
- The subflow version with the variable is not active. The Subflow element reads the interface of the active version. Saving a new version is not enough.
- The checkbox is not ticked. Obvious, and still the most common one.
- The parent flow was open the whole time. Flow Builder caches the subflow interface. Close the tab and reopen the parent.
- The types do not match. A record variable of a different object, or a collection where the subflow expects a single value, does not show as a valid source.
The activation rule catches people repeatedly because it inverts the normal development order. You cannot finish the parent against a draft subflow. Activate the subflow first, even in a sandbox, even when it is half-built.
Outputs are assigned when the subflow ends, not while it runs
The parent receives output values only when the subflow completes. If the subflow ends on a path where the output variable was never set, the parent gets null, not the value it had before the call, and the next element that reads it throws. Set every output variable on every terminating path, including fault paths, and give it something defensible like the text of the error.
In the parent’s Subflow element, tick Manually assign variables to choose where outputs land. Leave it off and the values are available as {!Subflow_Name.variableName} instead, which is fine for reading once and awkward for anything else.
A subflow is not a transaction boundary
This is the part that gets designed wrong. Calling a subflow does not start a new transaction. Parent and subflow share one set of governor limits: the same 100 SOQL queries, the same 150 DML statements, the same CPU budget. A subflow called inside a Loop consumes the parent’s limits, one full set of its elements per iteration.
They also share rollback. An unhandled fault anywhere in the subflow rolls back uncommitted DML from the whole transaction, including records the parent created before the call. If you need work to survive independently, the boundary has to be a Pause element or an asynchronous path, not a subflow.
Two further constraints are worth knowing before you plan a structure around subflows. Before-save record-triggered flows do not support the Subflow element at all, so a fast field update cannot be factored out into shared logic. And a screen flow can call an autolaunched subflow, but an autolaunched flow cannot call a subflow containing screens.
Frequently asked
Can I pass a record collection to a subflow? Yes, if the subflow’s collection variable is of the same object type and marked available for input. This is the right way to build a reusable “process these records” flow.
Which version of the subflow runs? The active one, at run time. That means activating a new subflow version changes the behaviour of every parent that calls it, with no change to the parents themselves, which is both the point of subflows and their main risk.
Do subflows show up separately in debug? Yes. The debug panel expands the subflow’s elements inline, and the debug log records the interview. Failed subflow interviews appear under Setup, Paused and Failed Flow Interviews, named after the subflow.
Is there a nesting limit? Flows can call flows several levels deep, but each level shares the same limits and each adds elements to the 2,000 executed elements budget. Two levels is usually plenty. Past three, the thing you want is probably an invocable Apex method.
