Back to insights

Flow Architecture, Contracts & Reuse

A subflow is not a reusable service

JSBC Labs8 min read

Visual reuse can hide runtime coupling

A team moves customer-risk logic into one autolaunched flow and calls it from onboarding, case escalation and contract renewal. The diagrams are smaller, so the design looks modular. A later change adds one query and one update to the subflow. Onboarding still passes, but the bulk renewal process now exceeds transaction limits and the case flow begins committing work that its owners never expected.

The JSBC Labs position is that a subflow is a reusable implementation unit, not automatically a reusable service. It has input and output variables, but it normally participates in the caller’s runtime, limits, data context and failure behaviour. Safe reuse requires a deliberate contract, controlled side effects, compatible calling contexts and release evidence for every consumer—not merely a tidy canvas.

Write the contract before drawing the elements

Name the capability in business terms: calculate renewal eligibility, resolve service ownership or validate onboarding evidence. Define required inputs, allowed nulls, output meanings, error outcomes and which records may change. Salesforce exposes only variables marked Available for Input or Output to callers; changing that visibility or removing an input can break components and flows that invoke it.

Prefer the smallest stable payload. Passing a complete Account record because one field is needed exposes every caller to accidental field coupling and stale values. Pass identifiers and explicit primitives when the subflow owns retrieval, or pass a record plus documented assumptions when the caller owns the snapshot. Return a result and reason code rather than forcing callers to infer success from whichever fields happened to change.

A subflow does not reset the transaction budget

Flows run inside Salesforce transactions and share per-transaction governor limits with the other automation in that unit of work. Moving Get Records, DML or Apex actions into a subflow does not make their cost disappear. A reusable subflow called once from a screen flow may be harmless and then fail when invoked repeatedly during bulk record processing.

Inventory queries, DML, callouts and loops across the complete call graph. Salesforce recommends collecting record changes and performing database work outside loops, and its Code Analyzer flags database operations in loops and circular subflow references. If the capability needs independent retry, high-volume computation or a separate commit, choose an asynchronous or programmatic boundary deliberately instead of assuming visual separation created one.

Security context is part of the public behaviour

Subflows can be used to separate work that respects user permissions from operations that run in system context. That is powerful, but it also makes a small reusable component a privilege boundary. A caller running in user context can pass an identifier into a system-context subflow that retrieves or updates data the user could not otherwise access.

Document the execution context and re-authorise sensitive operations inside the subflow. Expose only required inputs and outputs; Salesforce specifically warns that unnecessary system-context variables can reveal data. Treat browser-supplied IDs and values as untrusted, verify record scope and business entitlement, and never assume the parent flow’s screen or visibility rules protect a privileged subflow.

Active-version resolution creates release coupling

Salesforce documents that, for current API versions, screen and record-triggered flows call the active version of a referenced flow by default; if none is active, the latest version can be used. Activating a new subflow version can therefore change several parent processes even when none of their metadata is redeployed. That is dynamic linking, not isolated reuse.

Maintain a dependency register showing every parent flow, entry point, persona and business process that calls the subflow. Before activation, test the new version through each critical caller and confirm variable mappings, transaction volume and security context. Promote parent and child metadata in a controlled sequence, verify the active version in the target org and keep a known rollback version with compatible inputs and outputs.

Fault handling is a caller-facing contract

A fault path changes more than the message an administrator receives. Salesforce documents different rollback behaviour by flow type and by whether a fault path performs work. A subflow that catches an error, writes a log and returns normally may allow the parent transaction to continue; a propagated fault may roll back the wider operation. Neither choice is universally correct.

Classify failures as validation, authorisation, transient dependency, limit exhaustion or unexpected defect. Decide which ones the subflow resolves and which it returns to the caller. Use structured outcomes for expected business rejection and fault connectors for technical failure. Include correlation context in diagnostics without leaking sensitive data, and ensure a logging attempt cannot mask the original error or commit a partially valid business state.

Keep orchestration and capability ownership separate

The parent flow should decide when the capability runs and what happens next. The subflow should own one cohesive responsibility. When a reusable subflow queries unrelated objects, sends notifications, changes ownership and updates the originating record, every caller inherits an undocumented mini-process. Reuse then increases blast radius instead of reducing maintenance.

Separate pure decisions from side effects where practical. A calculation subflow can return eligibility and reasons; the parent can decide whether to update, notify or request approval. If complex data structures, partial-success DML, granular transaction control or performance at scale dominate the design, Salesforce’s automation decision guidance points toward Apex or a Flow-plus-Apex boundary rather than ever-larger declarative reuse.

Test the call graph, not only the component

Debug the subflow with boundary inputs, missing data, permission differences and collection volumes. Then test each parent because the same component can behave differently inside a record-triggered, screen or autolaunched transaction. Assert outputs, durable record state, error behaviour and absence of unintended side effects. Include bulk tests and a scenario where another automation consumes part of the same governor budget.

Operate the dependency as a product: assign an owner, monitor failures by caller and subflow version, review runtime and limit consumption, and remove consumers before retiring variables or versions. Salesforce Well-Architected guidance treats observability and automation governance as architectural concerns. The useful measure of reuse is not how many diagrams contain a Subflow element; it is whether one controlled change can improve every consumer without surprising any of them.

Official references

Continue reading