MuleSoft Flows and Subflows
A flow is the backbone of every MuleSoft application. It is a sequence of processing steps that a message goes through from start to finish. Understanding flows and subflows helps you build organized, reusable, and maintainable integrations.
What Is a Flow
A flow starts with a trigger — something that kicks off the processing. The trigger could be an incoming HTTP request, a scheduled timer, a message from a queue, or a file arriving in a folder. After the trigger, the message moves through a series of components that transform, route, log, or send it somewhere.
Flow Structure
+---------------------------------------------------------------------+ | FLOW: processOrderFlow | | | | [HTTP Listener] --> [Logger] --> [Transform] --> [Database] | | (Trigger) (Log request) (Convert JSON) (Save to DB) | +---------------------------------------------------------------------+
Every component in the flow processes the same message. Each component can read the message, modify it, or use its data to do something external like calling an API or saving to a database.
Types of Flows
Flow (Standard)
A standard flow has a message source (the trigger) and a series of processors. The trigger listens for events continuously. When an event arrives, the flow starts processing.
Private Flow
A private flow has no message source. It cannot be triggered directly from the outside. Other flows call it using the Flow Reference component. Private flows are like private functions in programming — useful for reusing logic without exposing it as an endpoint.
Subflow
A subflow is similar to a private flow but simpler. It inherits the error handling and variable scope of the calling flow. Use subflows for small reusable blocks of logic that belong logically to the parent flow.
Flow vs Private Flow vs Subflow
Flow: [HTTP Listener] --> [Logger] --> [Flow Reference: validateOrder] Has its own trigger. Starts when HTTP request arrives. Private Flow: "validateOrder" No trigger. Called by other flows. [Set Variable: isValid = true] --> [Logger] Subflow: "logOrderDetails" No trigger. Inherits parent's error handling. [Logger: "Order ID: #[vars.orderId]"]
Creating a Flow in Anypoint Studio
Open your project in Anypoint Studio. In the canvas, you see a blank flow area. Drag an HTTP Listener from the palette onto the canvas. Studio automatically creates a flow around it. The flow gets a default name like hello-worldFlow. Rename it by right-clicking on the flow title bar and selecting Rename.
Flow Reference Component
The Flow Reference component calls another flow or subflow from within the current flow. The called flow runs completely, then control returns to the original flow at the point after the Flow Reference.
Flow Reference Diagram
mainFlow:
[HTTP Listener]
|
v
[Transform: parse request]
|
v
[Flow Reference: validateInputSubflow] <-- Calls subflow
| <-- Control returns here after subflow finishes
v
[Database: save order]
|
v
[HTTP Response: 200 OK]
validateInputSubflow:
[Choice: is amount > 0?]
|-- Yes --> [Set Variable: valid = true]
|-- No --> [Set Variable: valid = false]
Message Scope in Flows
The message — payload, attributes, and variables — travels through the entire flow. Each component can read and modify the payload and variables. Variables set in a flow are available to subflows called from that flow, but not to completely separate flows.
Variable Scope Diagram
mainFlow:
[Set Variable: customerId = "CUST-001"]
|
v
[Flow Reference: lookupCustomerSubflow] <-- customerId available here
|
v
[Logger: vars.customerId] <-- Still available
lookupCustomerSubflow:
[Database: SELECT * WHERE id = #[vars.customerId]] <-- Can read it
[Set Variable: customerName = "Alice"] <-- Sets new variable
|
v
(returns to mainFlow)
Back in mainFlow:
[Logger: vars.customerName] <-- "Alice" is available because subflow shares scope
Synchronous and Asynchronous Flows
By default, flows run synchronously. The caller waits for the flow to finish before it receives a response. This is like calling someone on the phone and waiting for them to answer.
An asynchronous flow runs in the background. The caller gets an immediate acknowledgment and does not wait for the flow to finish. MuleSoft uses the Async scope for this. Place processing steps inside the Async scope to run them in the background while the main flow continues.
Synchronous vs Asynchronous
Synchronous:
Client --> [Flow starts] --> [Processes...5 seconds...] --> [Response] --> Client
Client waits 5 seconds
Asynchronous:
Client --> [Listener] --> [Async Scope: send email in background]
--> [Immediate Response: "Request accepted"] --> Client
(Email sends in background. Client does not wait.)
Error Handling in Flows
Every flow has an error handler section at the bottom. When something goes wrong inside a flow, MuleSoft stops the normal flow execution and enters the error handler. You configure the error handler to log the error, send an alert, return a specific error response, or retry the failed step.
Flow with Error Handler
+-----------------------------------------------------------------------+
| FLOW: saveOrderFlow |
| |
| [HTTP Listener] --> [Transform] --> [Database Save] |
| | |
| (if DB error occurs) |
| | |
| +------------------------------------------v---------------------+ |
| | ERROR HANDLER | |
| | [Logger: "DB save failed: #[error.description]"] | |
| | [Set Payload: {"error": "Order could not be saved"}] | |
| | [HTTP Response: status 500] | |
| +----------------------------------------------------------------+ |
+-----------------------------------------------------------------------+
Naming Flows Well
Good flow names make your application easier to understand and maintain. Use descriptive names that explain what the flow does:
- Bad name:
flow1,myFlow - Good name:
createCustomerFlow,processPaymentFlow,syncInventorySubflow
Add the word "Flow" or "Subflow" at the end of each name so you can instantly tell the type when reading the XML configuration or the Anypoint Monitoring logs.
Best Practices for Flows
- Keep each flow focused on one task. A flow that creates a customer should not also send the welcome email. Use a subflow or a separate flow for the email.
- Break long flows into smaller subflows. A flow with more than 15 components becomes hard to read.
- Always add an error handler to production flows. Never let errors silently fail.
- Use meaningful variable names so any developer can read the flow and understand it.
