Introducing - Mule Flow Diagrams [mulefd]

Mule applications are written in xml language with predefined XML schemas. Flows and sub-flows, along with other components are the base constructs of a Mule application. An application is usually a collection of multiple flows and sub-flows, spread across multiple configuration files. All of these can reference each other for processing messages. Often times, data can also be exchanged synchronously or asynchronously using connectors. When analyzing mule application, it can get difficult to see the complete data processing flow and their dependencies. In studio, you can keep jumping between flows to understand the processing flow but it is time consuming.

Have you ever wished to visualize your flow dependencies in a diagram? How does message flows through your application? Which sub-flows are called and in which order?

If yes, then this is for you!

Introducing Mule flow diagrams, a tool that can scan your mule projects and generate diagrams such as Graph of your mule application code.

Starting v0.5.0, CLI command is changed from muleflowdiagrams to mulefd. See this issue.

What does it do?

Consider following mule 4 configuration file that has some flows, sub-flow, and connectivity over VM and HTTP connector. Reading this XML or even seeing it in studio design mode may not easily tell how message flows through this application.

Click here to see an example test-hello-app.xml configuration.
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:db="" xmlns:http=""
      xmlns:doc="" xmlns:xsi="" xsi:schemaLocation="">
    <http:listener-config name="HTTP_Listener_config" doc:name="HTTP Listener config" doc:id="4b9901d3-7256-4899-ba42-e48244bb84fd" >
        <http:listener-connection host="" port="8081" />
    <db:config name="Database_Config" doc:name="Database Config" doc:id="6d07f955-b6c6-4bb6-8dde-8461669e29f2" >
        <db:my-sql-connection port="${db.port}" host="${db.hostname}"  user="${db.user}" password="${db.password}" database="${db.database}"/>

    <configuration-properties doc:name="Configuration properties" doc:id="f535d8b1-e94a-47d3-8280-192dfc7f53b4" file="" />
    <flow name="test-hello-appFlow1" doc:id="e8a2c60f-ec54-49af-85c7-6a4338658412" >
        <vm:listener doc:name="Listener" doc:id="cedb163e-e702-4c04-9695-712e59e2a0b4" config-ref="Messages_VM" queueName="messagesToProcess"/>
        <db:select doc:name="Select" doc:id="439a447d-3d96-4526-9b94-24e34bb9c938" config-ref="Database_Config">
            <db:sql >select * from books;</db:sql>
        <flow-ref doc:name="Flow Reference" doc:id="d606631b-f1f5-41d5-9ec8-9eec117bcc5b" name="sub-flow-level-1-1"/>
    <sub-flow name="sub-flow-level-1-1" doc:id="a33ad865-b9d8-4fbf-8d09-69d0b0300c99" >
        <logger level="INFO" doc:name="Logger" doc:id="dd241f4f-b7b7-4152-a532-999384753969" />
        <flow-ref doc:name="Flow Reference" doc:id="ae8ed341-07c1-4730-a728-8a5aa98b5e8d" name="sub-flow-level-2-1-1"/>
    <sub-flow name="sub-flow-level-2-2-0" doc:id="a33ad865-b9d8-4fbf-8d09-69d0b0300c99" >
        <logger level="INFO" doc:name="Logger" doc:id="dd241f4f-b7b7-4152-a532-999384753969" />
    <sub-flow name="sub-flow-unused" doc:id="a33ad865-b9d8-4fbf-8d09-69d0b0300c99" >
        <logger level="INFO" doc:name="Logger" doc:id="dd241f4f-b7b7-4152-a532-999384753969" />
    <sub-flow name="sub-flow-loop" doc:id="a33ad865-b9d8-4fbf-8d09-69d0b0300c99" >
        <logger level="INFO" doc:name="Logger" doc:id="dd241f4f-b7b7-4152-a532-999384753969" />
        <flow-ref doc:name="Flow Reference" doc:id="ae8ed341-07c1-4730-a728-8a5aa98b5e8d" name="sub-flow-loop"/>
    <sub-flow name="sub-flow-level-1-2" doc:id="5dced7e5-9fbc-4138-951f-586e0c1a766f" >
        <logger level="INFO" doc:name="Logger" doc:id="d451a2c2-a520-489a-8660-fb226a246f2a" />
        <flow-ref doc:name="Flow Reference" doc:id="1fb51667-42c9-4af6-9c7b-a3811e0e509a" name="sub-flow-level-2-2-0"/>
            <flow-ref doc:name="Flow Reference" doc:id="1fb51667-42c9-4af6-9c7b-a3811e0e509a" name="sub-flow-level-2-1-1"/>
        <flow-ref doc:name="Flow Reference" doc:id="1fb51667-42c9-4af6-9c7b-a3811e0e509a" name="sub-flow-level-2-2-1"/>
    <sub-flow name="sub-flow-level-2-1-1" doc:id="1d7a1a3a-777d-4d4b-8461-f11185247ae3" >
        <logger level="INFO" doc:name="Logger" doc:id="9e7481ed-b803-40a3-a720-3d9edf1b5500" />
    <sub-flow name="sub-flow-level-2-2-1" doc:id="da46a247-0355-4ace-a255-c28a19e628b9" >
        <logger level="INFO" doc:name="Logger" doc:id="2fabf827-7695-4830-ae9e-ec79eb38ba96" />
        <flow-ref doc:name="Flow Reference" doc:id="1fb51667-42c9-4af6-9c7b-a3811e0e509a" name="sub-flow-level-2-2-2"/>
    <sub-flow name="sub-flow-level-2-2-2" doc:id="da46a247-0355-4ace-a255-c28a19e628b9" >
        <logger level="INFO" doc:name="Logger" doc:id="2fabf827-7695-4830-ae9e-ec79eb38ba96" />
    <flow name="test-hello-appFlow" doc:id="c13c3670-cd7a-4181-bd9b-8d87f3f114d6" >
        <http:listener doc:name="Listener" doc:id="b0b19843-27ad-45c9-8761-2910af952655" config-ref="HTTP_Listener_config" path="/sayhello"/>
        <set-payload value="#['Hello from container']" doc:name="Set Payload" doc:id="2cfc464b-950a-4645-b7e3-355c5aeb7304" mimeType="text/plain"/>
        <flow-ref doc:name="Flow Reference" doc:id="f8c61d95-28e4-4c4a-8a51-27dc059b89b1" name="sub-flow-level-1-2"/>
        <flow-ref doc:name="Flow Reference" doc:id="f8c61d95-28e4-4c4a-8a51-27dc059b89b1" name="test-hello-appFlow1"/>
    <flow name="test-hello-appFlow-3" doc:id="c13c3670-cd7a-4181-bd9b-8d87f3f114d6" >
        <http:listener doc:name="Listener" doc:id="b0b19843-27ad-45c9-8761-2910af952655" config-ref="HTTP_Listener_config" path="/sayhello2"/>
        <vm:publish doc:id="7fdcd659-283b-40c7-9550-8b965fd8441f" sendCorrelationId="ALWAYS" correlationId="#[vars.formatType ++ '_' ++ ++ '_' ++]" queueName="messagesToProcess" doc:name="vm Publish" config-ref="VM_Config" transactionalAction="NOT_SUPPORTED" >
            <error-mapping targetType="APP:TRANSMISSION_QUEUE_FAILED" />
                <flow-ref doc:name="Flow Reference" doc:id="f8c61d95-28e4-4c4a-8a51-27dc059b89b1" name="sub-flow-level-1-2"/>
                <logger level="INFO" doc:name="Logger" doc:id="2fabf827-7695-4830-ae9e-ec79eb38ba96" />

Let’s generate a graph for this configuration file by running following command.

$ mulefd ~/Downloads/test-hello-app.xml -d GRAPH
Mule flow graph diagram - test hello app

What do we get from this diagram?

Now, this diagram tells us many things about our application code such as -

  • How are those flows and sub-flows linked to each other?

  • There is a sub-flow named sub-flow-unused which is potentially an unused sub-flow.

  • There is an asynchronous communication happening over VM.

  • Sub flow named sub-flow-loop is marked for a recursion condition.

Isn’t this easier to understand the application?

How to get this tool?

If you are on Mac OS, then you can get it via homebrew.

brew install manikmagar/tap/mulefd
If you have previously tapped this tool in homebrew but now getting error "Unsupported special dependency :java", that issue has been fixed. To refresh local tap, run brew untap manikmagar/tap first and then try brew install manikmagar/tap/mulefd again.

Alternatively, you can download the latest release from git repository and install it manually. See installation section on the repository.

You can make it out from the project repository path that this is by me and has no relation with MuleSoft.

How to use this tool?

It is a CLI tool and supports various arguments. Once you have it installed, you can run it from your terminal.

CLI Options
$ mulefd
Missing required parameter: '<sourcePath>'
Usage: mulefd [-hV] [-gs] [-d=<diagramType>] [-fl=<flowName>]
              [-o=<outputFilename>] [-t=<targetPath>] <sourcePath>
Create Flow diagrams from mule configuration files.
      <sourcePath>        Source directory path containing mule configuration
  -d, --diagram=<diagramType>
                          Type of diagram to generate. Valid values: GRAPH,
                            Default: GRAPH
      -fl, --flowname=<flowName>
                          Target flow name to generate diagram for. All
                            flows/subflows not related to this flow will be
                            excluded from the diagram.
      -gs, --genSingles   Generate individual diagrams for each flow.
  -h, --help              Show this help message and exit.
  -o, --out=<outputFilename>
                          Name of the output file
                            Default: mule-diagram
  -t, --target=<targetPath>
                          Output directory path to generate diagram
  -V, --version           Print version information and exit.

Copyright: 2020 Manik Magar, License: MIT

See Readme on project repository for more details on the usage.

For example, run the against a mule 4 project:

mulefd ~/devlife/AnypointStudio/studio-workspace/test-hello-app


It is evolving and more will come, so keep watching the repository for new releases. In meantime, please feel free to get the current release and try it out.

If you run into any issues or have suggestions, please open a new issue on project repository.

Still got a question, comment on this article or find me on Twitter. I am looking forward to hearing your thoughts on this.

on twitter to get updates on new posts.

Stay updated!

On this blog, I post articles about different technologies like Java, MuleSoft, and much more.

You can get updates for new Posts in your email by subscribing to JavaStreets feed here -

Lives on Java Planet, Walks on Java Streets, Read/Writes in Java, JCP member, Jakarta EE enthusiast, MuleSoft Integration Architect, MuleSoft Community Ambassador, Open Source Contributor and Supporter, also writes at Unit Testers, A Family man!