8.4 Calling Mule Flows from DataWeave & Reusing DataWeave Modules

Key Takeaways

  • Mule::lookup(flowName, payload, timeoutMillis) executes a flow from inside a DataWeave script and returns that flow's resulting payload.
  • lookup cannot call a subflow — the target must be a <flow>, and only the payload is passed: attributes and variables do not travel with the call.
  • The default lookup timeout is 2000 ms on CPU_LITE and CPU_INTENSIVE threads; exceeding it raises an error inside the transformation.
  • MuleSoft deprecated lookup in favour of a Flow Reference with the target attribute, which keeps orchestration in the flow where it can be traced and error-handled.
  • Reusable DataWeave lives in .dwl files under src/main/resources/modules and is pulled in with import … from dw::…, giving one definition for many transformations.
Last updated: August 2026

Calling Mule Flows from DataWeave & Reusing DataWeave Modules

Most DataWeave scripts are pure: data in, data out. But the exam blueprint contains an objective that breaks that assumption — call Mule flows from a DataWeave script — and a second one about defining and reusing modules, functions, and variables. Both are about the same underlying idea: stop duplicating logic, and reach for shared behavior from inside a transformation.


1. The Mule::lookup Function

The lookup function lives in the Mule module, which DataWeave auto-imports inside a Mule application, so both lookup(...) and the fully qualified Mule::lookup(...) resolve.

lookup(flowName: String, payload: Any, timeoutMillis: Number = 2000): Any
ParameterTypePurpose
flowNameStringName of the flow to execute, as a literal string
payloadAnyThe payload handed to the target flow
timeoutMillisNumberOptional; defaults to 2000 ms on CPU_LITE / CPU_INTENSIVE threads
<flow name="enrich-order-flow">
    <http:listener config-ref="HTTP_Listener_config" path="/orders" doc:name="Listener"/>

    <ee:transform doc:name="Enrich With Tax Rate">
        <ee:message>
            <ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{
  orderId: payload.orderId,
  subtotal: payload.subtotal,
  taxRate: Mule::lookup("getTaxRateFlow", { country: payload.country }).rate
}]]></ee:set-payload>
        </ee:message>
    </ee:transform>
</flow>

<flow name="getTaxRateFlow">
    <http:request method="GET" config-ref="Tax_API_Config" path="/rates" doc:name="Get Rate"/>
</flow>

The transformation calls getTaxRateFlow with a small object, that flow performs the HTTP call, and its resulting payload — { "rate": 0.0825 } — comes back as the value of the lookup expression.


2. The Four Restrictions That Get Tested

+-----------------------------------------------------------------------------------------+
|                          WHAT CROSSES THE lookup BOUNDARY                                |
|                                                                                         |
|   CALLING TRANSFORMATION                       TARGET FLOW                              |
|   payload    ---- (only the 2nd argument) --->  payload      YES                        |
|   attributes ---- X ------------------------->  attributes   NO (not transmitted)       |
|   vars       ---- X ------------------------->  vars         NO (not transmitted)       |
|                                                                                         |
|   RETURN:  target flow payload ONLY  <--------  (attributes/vars discarded)             |
+-----------------------------------------------------------------------------------------+
  1. Flows only, never subflows. lookup cannot invoke a <sub-flow>. Passing a subflow name is an error, and "call the subflow with lookup" is a reliable wrong answer.
  2. Payload only, in both directions. Attributes and variables are not transmitted into the target flow, and the target flow returns only its payload. A target flow that reads attributes.queryParams will find nothing there.
  3. It is bounded by a timeout. The default is 2000 ms when the transformation runs on a CPU_LITE or CPU_INTENSIVE thread (one minute on other thread types). A slow downstream call inside the target flow surfaces as a timeout raised inside the transformation, which is a confusing place to debug.
  4. Execution timing is not guaranteed. DataWeave is functional and lazily evaluated, so a lookup whose result is never used may not run at all, and multiple lookups may run in parallel. That makes lookup unsuitable for anything with side effects — never use it to write to a database or publish a message.

[!WARNING] lookup Is Deprecated — Know Both the Function and the Preferred Alternative MuleSoft deprecates lookup and recommends a Flow Reference with the target attribute instead: <flow-ref name="getTaxRateFlow" target="taxRate"/> puts the result in vars.taxRate where the transformation can read it, keeps orchestration visible in the flow, and lets normal error handlers catch failures. The exam can test either the function's mechanics or the recommendation, so learn both.

<!-- Preferred: orchestration stays in the flow, result lands in a variable -->
<flow-ref name="getTaxRateFlow" target="taxRate" doc:name="Get Tax Rate"/>
<ee:transform doc:name="Build Response">
    <ee:message>
        <ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{ orderId: payload.orderId, taxRate: vars.taxRate.rate }]]></ee:set-payload>
    </ee:message>
</ee:transform>

3. Reusing DataWeave: Variables, Functions, and Modules

The same blueprint domain expects candidates to define, use, and reuse DataWeave constructs. There are three levels, and questions usually turn on picking the right one.

ConstructDeclared withScopeUse when
Header variablevar taxRate = 0.0825One scriptA constant or precomputed value used repeatedly in that script
Header functionfun net(g) = g * 0.9One scriptLogic reused several times inside that script
Module (.dwl file)import … from dw::…Whole applicationLogic reused across several transformations

Building a Custom Module

A reusable module is a .dwl file placed under src/main/resources/modules/. The file path becomes its import path: src/main/resources/modules/OrderUtils.dwl is imported as modules::OrderUtils.

// src/main/resources/modules/OrderUtils.dwl
%dw 2.0

var STANDARD_DISCOUNT = 0.05

fun applyDiscount(amount: Number, rate: Number = STANDARD_DISCOUNT): Number =
    amount - (amount * rate)

fun tierOf(total: Number): String =
    if (total >= 10000) "PLATINUM"
    else if (total >= 1000) "GOLD"
    else "STANDARD"
%dw 2.0
import applyDiscount, tierOf from modules::OrderUtils
output application/json
---
payload map (order) -> {
    orderId: order.id,
    payable: applyDiscount(order.total),
    tier: tierOf(order.total)
}

The Three Import Forms

FormEffect
import dw::core::StringsMembers must be qualified: Strings::capitalize(x)
import capitalize, words from dw::core::StringsNamed members callable directly: capitalize(x)
import * from dw::core::StringsEvery member callable directly; risks name collisions

[!IMPORTANT] Modules Are Not Auto-Imported — Except a Few dw::Core is imported automatically, which is why map, filter, sizeOf, and now() work with no header line. Everything else — dw::core::Strings, dw::core::Arrays, dw::core::Binaries, and your own modules — needs an explicit import. An exam snippet that calls capitalize() with no import is broken, and the missing import is the defect the question is pointing at.

[!TIP] Reuse Across Applications Goes Through Exchange A module shared by one application belongs in src/main/resources/modules. Logic shared by many applications belongs in a library published to Anypoint Exchange and pulled in as a Maven dependency, which is the same reuse story as RAML fragments one layer down.

Test Your Knowledge

A developer writes Mule::lookup("validateAddressSubFlow", payload) inside a Transform Message component. The target is defined in the application as <sub-flow name="validateAddressSubFlow">. What happens?

A
B
C
D
Test Your Knowledge

A Transform Message component calls Mule::lookup("fetchCreditScoreFlow", payload). Inside fetchCreditScoreFlow, a Logger tries to read attributes.queryParams.customerId and vars.correlationRef, both of which exist in the calling flow. What does the target flow see?

A
B
C
D
Test Your Knowledge

A team wants one definition of a customer-tier calculation shared by six different Transform Message components across three XML files in the same Mule project. Which approach matches MuleSoft guidance?

A
B
C
D
Test Your Knowledge

A DataWeave script begins with %dw 2.0 / output application/json and its body calls capitalize(payload.name) and map over payload.items. The script fails to compile on capitalize but the map operation is fine. What is the cause?

A
B
C
D