Back to insights

Flow Architecture & Reuse

A subflow is an API contract—not a diagram shortcut

JSBC Labs8 min read

Reuse creates a contract

A subflow can remove duplicated decisions and data operations from several Salesforce automations. Salesforce's Well-Architected guidance recommends a hierarchy of main flows and supporting subflows, with each flow serving a specific purpose. That is sound modular design—but the moment multiple callers depend on one subflow, it stops being a convenient piece of canvas and becomes a shared interface.

The JSBC Labs position is that reusable subflows should be governed like internal APIs. Their variable API names, data types, outcomes, execution assumptions and failure behaviour are promises to callers. A visual builder does not make those promises less consequential. An apparently small change can break a screen flow, record-triggered flow or orchestration that another team owns.

Name the business capability first

Good subflows express a stable capability: calculate eligibility, resolve a routing destination or apply governed defaults. Weak subflows are named after implementation fragments such as Update Records Two or Shared Logic. Those fragments attract unrelated callers, then accumulate branches until nobody can explain their actual contract.

Write a one-sentence responsibility before building. Define what the subflow may read, what it may change and what remains the caller's responsibility. Keep routing and experience-specific decisions in the parent flow when they vary by channel. Reuse the policy or operation that is genuinely common. A subflow with one coherent reason to change is easier to test, secure and retire.

Make inputs deliberately small

Salesforce exposes variables marked available for input to a Subflow element, and the caller assigns those values at run time. Treat that list as the public request schema. Do not expose every local variable for future convenience. Each input increases coupling, creates another validation case and gives callers knowledge of implementation details that will be difficult to remove later.

Prefer the minimum stable identifiers and business values needed to perform the capability. Passing an entire record can be useful when the contract truly concerns that record, but it also couples callers to fields, load state and later mutation. Document required versus optional inputs, null behaviour, collection expectations and accepted values. Validate at entry so an invalid request fails predictably instead of producing a misleading partial outcome.

Return outcomes, not internal machinery

Output variables form the response schema. Salesforce lets the parent reference outputs from the Subflow element or assign them to variables. That does not mean the child should return every intermediate value. Exposing queried records, temporary flags and calculation steps makes the parent dependent on how the work is implemented rather than what the work achieved.

Return business outcomes that the caller can act on: an approved destination, a calculated amount, a result code or a deliberately shaped record collection. Avoid one ambiguous Boolean whose meaning changes by branch. Pair an outcome with concise context when a caller needs to present or log it. Stable, meaningful responses allow the implementation to evolve without forcing coordinated edits across every parent flow.

The transaction boundary still matters

A Subflow element organises logic; it is not, by itself, a promise of a new transaction or additional governor budget. The child's queries, data operations, invocable Apex and callouts contribute to the work initiated by the parent unless the architecture introduces an explicit supported boundary. Nesting a heavy operation behind a tidy element can therefore make the canvas cleaner while leaving the runtime risk unchanged.

Document whether the capability is expected to run before save, after save, from a screen or in an asynchronous path. Count the combined workload under bulk conditions and include automation that the subflow's data changes will trigger. If the operation requires isolation, long-running coordination or independent recovery, choose the appropriate asynchronous or orchestration pattern rather than assuming modular presentation provides operational separation.

Failure semantics belong in the interface

A reusable operation needs a defined distinction between an expected business outcome and a technical failure. Ineligible, duplicate or not found may be valid results that the parent handles through normal decisions. A failed DML operation, unavailable dependency or violated invariant is different. Converting every problem into a false flag destroys that distinction and makes support teams reverse-engineer the cause from side effects.

Specify which outcomes are returned, which faults propagate and what the caller must do. Give parent flows fault paths for operations that can fail, but do not let every caller invent different compensation for the same shared capability. Centralise safe diagnostics and correlation data while keeping user-facing messages appropriate to the channel. Never catch a fault merely to continue with state that may now be incomplete.

Execution context is part of correctness

A subflow can be called from parents launched in different contexts, identities and channels. The same data operation may be acceptable for an internal record-triggered process and unsafe for an externally launched screen flow. Salesforce's security guidance for system-context flows emphasises protecting input and output data; reuse must not become an accidental privilege bridge.

State the expected caller types, user context and data classification in the contract. Minimise exposed fields, validate record identifiers and test with users who have materially different permissions and sharing. If a capability intentionally performs elevated work, isolate that responsibility and enforce its own eligibility checks. The parent flow's convenience is not sufficient authorisation for the child to read or change sensitive data.

Version for consumers, not only authors

Salesforce runs the active version of a referenced subflow, and the Subflow element surfaces variables from the active and latest versions while authors configure it. Activating a new child version can therefore change behaviour for several parents at once. Salesforce also warns that disabling input or output access on an existing variable can break applications and pages that call the flow.

Treat variable removal, renaming, type changes and semantic reinterpretation as breaking changes. Prefer additive evolution: introduce a new optional input or output, migrate callers, observe them and only then retire the old contract. Maintain a consumer inventory and release the subflow with its affected parents as one change set. When compatibility cannot be preserved, publish a new subflow API name instead of silently redefining the old one.

Test the contract at two levels

Direct tests should prove the subflow's behaviour across valid, invalid, empty, bulk and permission-sensitive inputs. They should assert business outcomes and durable state rather than canvas element order. Salesforce CLI can run Flow tests and retrieve results, which makes Flow behaviour a candidate for continuous integration rather than a manual pre-release demonstration.

Contract tests must also exercise representative parents. They catch mapping errors, changed defaults, fault-path gaps and assumptions about context that isolated child tests cannot see. Add those tests to the deployment gate when a shared subflow or exposed variable changes. A green child test does not prove that ten callers still send the right request or interpret the response consistently.

Give shared automation an owner

Record the subflow's purpose, owning team, consumers, inputs, outputs, context, side effects, expected faults and operational signals in source control beside the metadata. Assign a support path and a deprecation process. Monitor failures by capability and caller so a shared defect is visible as one incident rather than a series of apparently unrelated broken flows.

Subflows are an excellent way to make Salesforce automation modular, readable and reusable. The design succeeds when reuse reduces change risk—not merely when it reduces element count. A small contract, explicit context, compatible versioning, predictable failures, automated tests and named ownership turn a visual shortcut into a dependable platform capability. That is the standard shared automation deserves.

Official references

Continue reading