Flow - lightweight fast template engine using Split twice

Technique 2 β€” Building a Lightweight Template Engine (Using Split Twice)

Take this example (using a handle-bar stil syntax)

ABC {{def}} GHI {{jkl}} MN

Using a dictionary (Compose)

{
  "def": "fish 🐟",
  "jkl": "chips 🍟"
}

We want to build a mini-template engine.
Now you might think - ah ok, let’s get some variables in here.

But John really dislikes variables in fact most of these flow hacks are how to not use variables. So how do you do this without variables?

1. Split on {{

split(outputs('Compose'), '{{')

result

[ 
  "ABC ",
  "def}} GHI ",
  "jkl}} MN"
]

2. Split each on }}

inside each item, split again

split(item(),'}}')

So now our original string becomes either:
["ABC "]

or

["def"," GHI "]

Recap, combine step 1 and 2

Select:
  from: split(outputs('Compose'), '{{')
  item: split(item(), '}}')

3. Conditional replacement using dictionary lookup

if(
  equals(length(item()),2),
  concat(
    outputs('Dictionary')?[item()?[0]],
    item()?[1]
  ),
  item()?[0]
)

Hidden insight

So the trick is this. If the row has 2 elements, that means the first element is a token, the rest is the remainder. If the row has only 1 element - then just return that.

[
  item()[0],
  dictionary[item()[0]] item()[1],
  dictionary[item()[0]] item()[1]
]
==>
[
  "ABC",
  "fish 🐟 GHI",
  "chips 🍟 MN"
]

If you want your dictionary lookup to be case insensitive, you can add toLower() to wrap around item()?[0]

4. Join it all together

join(body('Select'),'')

Result

ABC fish 🐟 GHI chips 🍟 MN

No loops.
No apply-to-each.
No regex.
No variables.
Super fast zero-second action.

This technique lets you:

  • Build dynamic email templates

  • Create server-side HTML rendering logic

  • Replace merge fields safely

  • Do token replacement in Dataverse text

  • Build dynamic document generators

All using standard Power Automate expressions.


About: The old trigger URL will stop working on November 30, 2025

Starting in August 2025, we’ve begun to see this warning a lot in our Power Automate flows that uses HTTP Request (or Team Webhook) triggers.

β€œThe old trigger URL will stop working on November 30, 2025. Your tools that use this flow WILL break unless you update them with the new URL.”

The old url uses the logic app domain:

https://*.logic.azure.com/workflows/{flow-name}/triggers/manual/paths/invoke

The new URL uses a largely undocumented api.powerplatform.com domain.

https://{environment-name}.environment.api.powerplatform.com/powerautomate/automations/direct/workflows/{flow-name}/triggers/manual/paths/invoke

Why New URL?

The NEW URL looks to be more future proof and ties the invoke URL to the environment and flow name within Power Platform, rather than the underlying logic apps infrastructure.

Microsoft’s documentation is here: Changes to HTTP or Teams Webhook trigger flows

Flow Studio new feature: Flow (Request) Report

To help with updating these URLs, we decide to put in a special View and Report for this in Flow Studio. Here, we are doing 4 things:

  • This report shows flows that use the "When an HTTP request is received" trigger. These flows can be triggered externally via HTTP requests, making them suitable for integration scenarios.

  • First we do a scan of all the environments and find all your flows that use this trigger. This may take a few minutes depending on the number of environments and flows.

  • Then for each flow we will need to check the flow definition to extract the old and new request URL and method.

  • We also need to check the flow's run history to see if it has been triggered recently. This will help us identify active flows.

We present this in a quick table for you to browse, but also provide an Export to Excel functionality so you can decide how you want to tackle the list.

Permissions

Because of the API access we need to read definition and trigger callback URL, this is not a scan we can do at the admin level - it has to be the owner of the flows.

You can find this new feature in our dev build:
https://dev.flowstudio.app

Diff Mode in Flow Studio

We are happy to introduce a new feature update in Flow Studio app. β€œDiff Mode”

  • Navigate to Diff on the left hand side.

  • Use the top dropdowns to select your environment, flow and (optionally) version. Hit β€œLoad”

  • You can use Monaco (VS Code) editor to copy Flow definition differences to the right hand side.

  • The left hand side is always read-only.

  • Clicking β€œSave” will save the right hand side flow definition.

This is a feature previously hidden in β€œSnapshots” and β€œDiff” flow. But that experience only lets you compare between the flow and its previous versions. The new experience also let you compare a flow between two different environments. So if you have Dev, Test and Prod environments with unmanaged solutions - you may need this to keep your flows in sync.

Do test this out in https://dev.flowstudio.app v1.3.58 for now and give us your feedback. We’ll aim to push this to production build within 1 week.

Thank you for supporting Flow Studio App


Mathematically Elegant way to Flatten an Array of Arrays in Power Automate

When working with data in Power Automate, you may encounter nested arrays (arrays within arrays)β€”especially when dealing with JSON responses, SharePoint lists, or API results. However, many Power Automate actions require a flat array to work properly.

In this post, I'll show you a mathematically elegant way to flatten an array of arrays into a single-level array using Power Automate expressions.

Understanding the Problem

Let's say you have the following array:

[
    ["Ford", "Toyota"],
    ["BMW", "Audi"],
    ["Honda", "Nissan"]
]

Instead of dealing with nested arrays, you want to flatten it into a single array:

["Ford", "Toyota", "BMW", "Audi", "Honda", "Nissan"]

The slow way - Array variable

The slow way is to use an array variable, then while looping through the top level array, append or union the results into the array variable.

Variables are so slow I don’t even want to make them and add a picture.

The faster way - String manipulation

Convert the array into JSON string, remove the extra array [ and ] characters, re-construct the array in string, and convert back to JSON.

This is a method I was using, it’s much quicker, but has a risk of needing to be careful when removing bracket characters. If you have nested JSON objects this needs more care.

The new fastest way - div and mod flattening

To understand this - you need two numbers: m and n
m = number of elements in the top array
n = number of elements in the child array

Create a range of the total result size of the array (m) * (n)

Use select - loop through this range of numbers, then for each, select the nested result using:
outputs(β€˜nested-items’)?[ div( item(), outputs(β€˜n’)) ]?[mod( item(), outputs(β€˜n’)) ]

do you see how elegant this is πŸ€”

From:
range(
  0, 
  mul( 
    length(outputs('Nested_Array')),
    outputs('Compose_-_child_size')
  )
)

Map:
body('Nested_Array')
?[div(item(),outputs('Compose_-_child_size'))]
?[mod(item(),outputs('Compose_-_child_size'))]

what’s going on here?
let’s picture for each of the 6 elements above.

0 = array[0][0] div(0, 2) = 0, mod(0,2) = 0
1 = array[0][1] div(1, 2) = 0, mod(1,2) = 1
2 = array[1][0]
3 = array[1][1]
4 = array[2][0] div(4, 2) = 2, mod(4,2) = 0
5 = array[2][1]

so in one select, we can flatten an (m * n) -sized array.

What if my child array is irregularly sized?
That’s OK. By using ?[n] Select will return null for that element, so we can follow the select with a filter-array to remove the nulls.

Bonus

This works wonderfully with Pieter’s Method, which returns array of Body jsons.

Bonus

This works well for cross-join of two arrays, and then flattening them into one.
(These bonus ideas are massive additional blog posts let me know if want to read them…)

A debug tip for complex conditions in Power Automate #FlowNinjaHack 126

This is #FlowNinjaHack 126

Sometimes, we have complex Condition blocks in Power Automate.

And when we run the flow, it just shows β€œfalse”, which is a bit hard to debug.

One way I’ve started doing, is to write a Compose debug statement that shows the output of each component of my condition.
I show the Code View here as well so you get the idea.

To convert from the Condition block to these expressions can be a bit tricky, since you can’t use Code View easily for Condition. So here’s a second hack.

Paste this to a text editor, something that understands JSON. You’ll get this part.

        "type": "If",
        "expression": {
            "and": [
                {
                    "not": {
                        "equals": [
                            "@outputs('Get_item_-_Bulletins_list')?['body/Status/Value']",
                            "Draft"
                        ]
                    }
                },
                {
                    "not": {
                        "contains": [
                            "@body('Select_page_filename')",
                            "@variables('varTitle')"
                        ]
                    }
                },
                {
                    "contains": [
                        "@body('Select_page_filename')",
                        "@outputs('Compose_-_Old_Title')"
                    ]
                }
            ]
        }

Now this is still not the right format, but you can then go from this to:

not(contains(body('Select_page_filename'), outputs('Compose_-_Old_Title'))

With a lot less pain.
This is the debug message you’ll see when you run now.