Are the Active Versions of my Flows the Most Recent Versions?

Created by Eric Smith

Why would one want to know if the active version of a flow is the most recent version?

There are a couple of reasons why I need to know this information.

  1. I am deploying a large Project from a Sandbox to a Production org where by default, active flows are deployed as inactive.  I then have to manually reactivate each of the new flow versions and at some point I need to confirm that I have reactivated each of the deployed flows.
  1. I use subflows and I’m affected by a Salesforce bug* where the latest version of a subflow is executed instead of the currently active version of the subflow.  This can cause issues for users in an environment where testing is occurring at the same time updates are being developed and applied.

* Known Issue: The latest Subflow is run instead of the active Subflow

To manually check what versions of a flow are in an org, you start in Setup with the Flows Listview.  Then you click on the row action icon to the far right and select “View Details and Versions”.

A list of all the versions of the flow will be displayed with “Deactivate” displayed on the row showing the version that is currently active.  If any newer, inactive, versions are there, they will be displayed above the active version.

As you can imagine, this will be a long manual process to go through each one of your flows to see if the most recent version is the active version.

To make this process quick and easy, I created a flow that gets records from a couple of Salesforce Objects that store information about the flows in the org. One is FlowDefinition which stores the active version number of a flow and the other is FlowVersion which has a separate record for every version of a flow.  You are restricted when querying FlowVersion in that you can’t do a Get Records on the object unless you restrict the query to a single flow id.

When you run the flow, it will display a list of those flows where the active version of the flow is not the most recent version along with another list of flows that have no active version.

If you have my Datatable flow screen component installed in your org, you can install a version of the flow that uses the Datatable to display the results.

How it Works

Read on if you are interested in how I built this flow and what makes it work.  Click here to skip right to the installation links.

The first Get Records queries the Flow Definition object to get a collection of flows.  Since this object also stores information about Process Builders and other automations, I restrict my records to just those with a Process Type of AutoLaunchedFlow or Flow. I sort the records by the flow Label so the results will show in alphabetical order.

Then the flow Loops through each of the Flow Definition records.

The first decision checks to see if the Latest Version is the Active Version

{!Flow_Definitions.ActiveVersionId} Equals {!Flow_Definitions.LatestVersionId}

If the versions don’t match, I query the FlowVersion object for that flow to get the latest version of the flow.  I sort the retrieved records by VersionNumber from the largest to the smallest and I just take the first record in that collection.

FlowDefinitionViewId Equals {!Flow_Definitions.DurableId}

The other decision is to check if the flow has no active version.

{!Flow_Definitions.ActiveVersionId} Is Null True

Depending on the outcome of that decision I use an Assignment to add the details about the current flow to one of my two collections to be displayed at the end of the flow.

The final node in the flow is a Screen that uses Display Text to show the two lists I built in the flow.

If you made it this far and want to see how I built and formatted the output, I have some more goodies for you.

Each of the lists being displayed are just Text variables that are built up as I process each record in my loop.

I do this by Adding text with a flow Formula that has the formatting for each line.

For example, the formula for fFlowEntry is this:

LPAD( TEXT( {!Flow_Definitions.VersionNumber} ), 5, CHR(0160) ) & 
LPAD( TEXT( {!Get_Latest_Flow_Version.VersionNumber} ), IF( {!Flow_Definitions.VersionNumber} > 99, 7, IF( {!Flow_Definitions.VersionNumber} > 9, 8, 9 ) ), CHR(0160) ) & 
LPAD( CHR(0160), IF( {!Get_Latest_Flow_Version.VersionNumber} > 99, 4, IF( {!Get_Latest_Flow_Version.VersionNumber} > 9, 5, 6 ) ), CHR(0160) ) & 
{!Flow_Definitions.Label} & 

To help line everything up, I’m using the LPAD functions to put a certain number of spaces before each of the values that make up a row in my output table.  The IF functions are used to calculate how many spaces I want.  For example, if the VersionNumber is 107, I’ll want fewer spaces separating the values than if the VersionNumber was just a single digit like 5.

I use CHR(0160), which is a non-break space, instead of a regular space because Salesforce and browsers will often collapse multiple spaces to just a single space which would cause the output not to line up very well.

Without CHR(0160)
With CHR(0160)

The final piece of the puzzle is the fCRLF formula, which is used to insert a line break between each row of my output.

This starts with a plain text Text Template that is just two ~ characters separated by a line break.  



The formula uses the SUBSTITUTE function to remove the ~ characters leaving just the line break.


SUBSTITUTE({!ttCRLF}, "~", "")

Installation Links

A flow that queries all flows in the org and displays a list of flows where the most recent version of a flow is not the active version and another list of flows with no active version.

Production or Dev


A flow that queries all flows in the org and displays a list of flows where the most recent version of a flow is not the active version and another list of flows with no active version.  This flow is for orgs that have Eric Smith’s Datatable component installed.

Production or Dev