Free guide

Power Automate: 50 tips for fast and stable cloud flows.

Flows that hang, keep failing, or exceed limits cost time and trust. Here I have collected 50 recommendations for fast and stable Power Automate cloud flows: from trigger conditions and targeted queries through loops, expressions, and error handling to limits, solutions, and operations. Free and without registration.

  • 50 tips
  • 8 topic areas
  • 16 tips you can implement quickly
  • Free without registration

01Why it pays off

Good flows just run.

Cloud flows do work in the background that people would otherwise have to do. They need to run reliably, use resources efficiently, and make it clear what happened. Three reasons why the effort pays off.

Reliability

Stable flows keep running, even when something goes wrong.

Cloud flows often handle tasks people no longer think about: routing approvals, synchronizing data between systems, and sending notifications. A failure often goes unnoticed until a case stalls or the data becomes inaccurate.

A stable flow expects errors. It retries temporarily failed calls, catches permanent errors cleanly, reports them with all necessary information, and leaves no half-processed data behind. This keeps the process reliable, even if a target system temporarily fails to respond.

Capacity and costs

Every action saved conserves request capacity and budget.

In Power Automate, every action counts as a request against the license limits, including variables, conditions, retries, and additional pages loaded. A flow that executes unnecessary steps for every record quickly uses up this capacity and risks being throttled.

Lean flows with trigger conditions, targeted queries, and data operations instead of loops need significantly fewer actions. They run faster, put less load on data sources, and help you stay within the allowances of your existing licenses for longer. In environments with pay-as-you-go billing, runs with premium connectors can also incur costs if they are not covered by a license.

Scalability

Good flows grow with the data volume.

Many flows work flawlessly with a few test records and falter as soon as there are thousands. Then limits kick in that played no role before: pagination, items per loop, connector throttling, or the maximum run duration.

A well-planned flow is designed for growth from the start. It filters in the data source, processes data in batches, can be moved cleanly between environments as part of a solution, and does not depend on individual people. This way, it can handle increasing volumes without having to be rebuilt.

02The path of a flow

Where a flow loses time.

Every run starts with the trigger, works through actions and loops, calls connectors and data sources, and must be monitored in production. Time can be saved at every step. The numbers link directly to the relevant tip.

  1. Trigger

    When and how often a flow starts, and how quickly it responds.

    Related tips:123456

  2. Actions & loops

    Loops, data operations, expressions, and error handling in the flow.

    Related tips:131415161718192021222324252627282930

  3. Connectors & data sources

    SharePoint and Dataverse, request limits, throttling, and sizes.

    Related tips:7891011123132333435

  4. Solution & operations

    Solutions, connections, permissions, tests, and monitoring around every run.

    Related tips:3637383940414243444546474849

03The recommendations

50 tips for better performance.

Sorted into eight areas. Search for a keyword, filter by area or by tips that can be implemented directly in the flow, and mark the tips you have already implemented. Finally, tip 50 shows why it is worth it. The examples show expressions, trigger conditions, OData filters, and JSON from the code view.

Triggers & runs

Trigger conditions, filters in the trigger, schedules, and concurrent runs · 6 tips

Trigger conditionsQuick to implement

Tip 1: Avoid unnecessary runs with trigger conditions

Many flows start on every change and only then check with a condition whether there is anything to do at all. Each of these runs counts against the request limits, even if it ends immediately.

Trigger conditions perform this check at the trigger stage. If the condition is not met, the flow does not start, and no run history entry is created. By default, multiple conditions must all be met; use or() to combine them with OR.

Recommendation

Move simple checks from the flow into the trigger settings under "Trigger conditions." Each condition starts with the @ character.

Trigger condition · example
// Only items with the status "Approved" (SharePoint choice column)
@equals(triggerOutputs()?['body/Status/Value'], 'Approved')

Area: Triggers & runs

Infinite loopsQuick to implement

Tip 2: Prevent infinite loops

If a flow changes exactly the item that triggered it, it triggers itself again. This can create a loop that constantly generates new runs and consumes requests.

Recommendation

Exclude changes made by the flow itself with a trigger condition, for example based on the person who last modified the item. This works particularly reliably if the flow writes with its own service account.

Trigger condition · example
// Do not start if the flow's service account last modified the item
@not(equals(triggerOutputs()?['body/Editor/Email'], 'serviceaccount@example.com'))

Area: Triggers & runs

Dataverse triggerQuick to implement

Tip 3: Limit Dataverse triggers to relevant changes

The Dataverse trigger "When a row is added, modified or deleted" offers two filters of its own. "Select columns" determines which columns start the flow when changed. "Filter rows" uses an OData expression to check whether the changed row is relevant at all.

Important: the flow starts as soon as one of the selected columns is included in the change, even if its value has not changed. Lookup columns are not supported in "Select columns."

Recommendation

For change triggers, enter only the columns the flow should really react to, and no columns that are sent with every change. Add a row filter if needed.

OData filter · example
// Select columns
statuscode

// Filter rows
statecode eq 0

Area: Triggers & runs

Schedule

Tip 4: React to events instead of constantly checking

Scheduled flows that check every minute, for example, whether there is new data also run when there is nothing to do. Each of these runs consumes actions and therefore requests. The shortest possible interval of a schedule is 60 seconds.

Recommendation

Wherever possible, use an event-based trigger from the data source. If a schedule is necessary, set the longest interval your process allows and process all accumulated records in a batch each run.

Area: Triggers & runs

Concurrency control

Tip 5: Control concurrent runs deliberately

By default, a flow starts a separate run for each event, without limit. If many events arrive at the same time, numerous runs access the same data simultaneously. This can cause conflicts and throttling.

With the trigger's concurrency control, you limit the number of simultaneous runs to a value from 1 to 100 (default when control is turned on: 25). Additional runs wait in a limited queue until a slot becomes free.

Recommendation

Turn on concurrency control if runs must not process the same records at the same time or if a target system can only handle a few requests. With the value 1, runs execute one after another.

Area: Triggers & runs

Response time

Tip 6: Don't keep callers waiting

When an app or another system starts a flow and waits for the result, every second counts. Incoming requests and synchronous responses are limited to 120 seconds. If it takes longer, the caller receives a timeout.

Recommendation

Send the response ("Respond to a Power App or flow" or "Response") as early as possible, as soon as the result is known. The flow handles follow-up work such as logs or emails afterward.

Area: Triggers & runs

Querying & filtering data

Filter queries, column selection, pagination, and batch requests · 6 tips

Filter query and Top CountQuick to implement

Tip 7: Filter query and Top Count instead of fetching everything

Without a filter, "Get items" returns all items in a list, and the flow filters them afterward. This takes time, uses memory, and transfers unnecessary data.

With an OData filter query, SharePoint already filters on the server. By default, the action returns 100 items. Using "Top Count," you can increase the number up to the list view threshold of 5,000 items or lower it to the amount actually needed.

Recommendation

Filter and sort in the query itself and limit the number via "Top Count" if, for example, you only need the latest item. In Dataverse, the counterparts are called "Filter rows" and "Row count."

OData filter · example
// Filter query
Status eq 'Open' and Department eq 'Sales'

// Order by
Created desc

Area: Querying & filtering data

Select columnsQuick to implement

Tip 8: Retrieve only the required columns in Dataverse

Without any specification, "List rows" returns all columns of a table. The more columns, the larger the response and the longer retrieval and processing take in every subsequent step.

Recommendation

Enter the logical names of the required columns, separated by commas, under "Select columns," and combine this with "Filter rows."

OData filter · example
// Select columns
name,emailaddress1,telephone1

// Filter rows
statecode eq 0 and createdon ge 2026-01-01T00:00:00Z

Area: Querying & filtering data

Columns by viewQuick to implement

Tip 9: Limit columns in SharePoint via a view

By default, "Get items" returns all columns of a list, including lookup, person, and calculated columns that SharePoint must resolve first. With wide lists, this makes the response large and slow.

Recommendation

Create a view in the list with exactly the columns the flow needs, and select it in the advanced options under "Limit Columns by View."

Area: Querying & filtering data

Pagination

Tip 10: Use pagination deliberately

Many actions return only one page of results; "List rows" in Dataverse, for example, returns up to 5,000 rows. If you need more, turn on pagination in the action's settings and set a threshold. The maximum number of items depends on the performance profile: 5,000 in the "Low" profile and 100,000 in all others. Every additional page loaded counts as a request.

For SharePoint lists with more than 5,000 items, pagination is important even with a filter. Otherwise, the result may remain empty if there is no match among the first 5,000 items.

Recommendation

Turn on pagination only where you really need more than one page, and set the threshold appropriately. For even larger data volumes, distribute the processing across several runs.

JSON · example
// Action settings in code view
"runtimeConfiguration": {
    "paginationPolicy": {
        "minimumItemCount": 20000
    }
}

Area: Querying & filtering data

Expand query

Tip 11: Get related data in one query

A common pattern: the flow lists rows and then retrieves the related record for each row in a loop. With a hundred rows, that is a hundred additional requests.

Recommendation

In "List rows," use the "Expand Query" field and fetch the required columns of the related table at the same time. Limit the columns there with $select as well.

OData filter · example
// Expand query: only two columns of the primary contact
primarycontactid($select=contactid,fullname)

Area: Querying & filtering data

Batch requests

Tip 12: Bundle many SharePoint changes

If a flow creates or changes many items individually in a loop, each item generates its own request. This takes time and increases the risk of throttling.

The SharePoint REST API supports batch requests: via the _api/$batch endpoint, you combine several operations in a single request. In Power Automate, you send it with the "Send an HTTP request to SharePoint" action. The operations in a batch are not transactional; if one fails, the others still run.

Recommendation

Use $batch for large numbers of similar changes and evaluate the response for each operation. For a few items, the additional effort is usually not worth it.

Area: Querying & filtering data

Loops & concurrency

Filter array and Select, Apply to each, Do until, and child flows · 7 tips

Filter arrayQuick to implement

Tip 13: Filter array instead of a loop with a condition

An "Apply to each" loop with a condition inside executes at least two actions for each item. Every action counts as a request and costs time.

"Filter array" ("Array filtern" in the German UI) reduces an array to the matching items in a single step. Note that the text comparison is case-sensitive.

Recommendation

Use "Filter array" to filter arrays, and if a loop is needed, iterate only over the matches. Write complex conditions as an expression in advanced mode.

Expression · example
// Filter array, advanced mode
@and(equals(item()?['Status'], 'Open'), greater(item()?['Amount'], 1000))

Area: Loops & concurrency

SelectQuick to implement

Tip 14: Reshape data with Select instead of a loop

To prepare data for an email, a table, or an integration, many flows build a new array in a loop with "Append to array variable." This is slow and cannot be safely parallelized.

"Select" ("Auswählen" in the German UI) reshapes all objects in an array in one step. You can add, remove, or rename fields; the number of objects stays the same.

Recommendation

Use "Select" for reshaping and then, if needed, "Create HTML table," "Create CSV table," or "Join." This way, you need no loop for the preparation.

JSON · example
// Select, mapping in text mode
{
    "Number": "@item()?['Title']",
    "Customer": "@item()?['Customer']",
    "Amount": "@item()?['Amount']"
}

Area: Loops & concurrency

ConcurrencyQuick to implement

Tip 15: Run Apply to each in parallel

By default, "Apply to each" processes items one after another. If the iterations are independent of each other, you can turn on concurrency in the settings and set a value from 1 to 50.

A high value does not automatically make the loop faster. Splitting up the work and the target system's response time also cost time, and many simultaneous requests can lead to throttling.

Recommendation

Turn on concurrency for independent iterations and work your way toward a suitable value. Check beforehand whether variables are changed in the loop (see tip 16).

Area: Loops & concurrency

Variables in loops

Tip 16: Don't change variables in parallel loops

When iterations run in parallel, they access the same variable at the same time. Actions such as "Increment variable," "Decrement variable," or "Append to array variable" can then produce unpredictable results, for example wrong totals or missing entries.

Recommendation

In parallel loops, use "Compose" instead of variables and collect the results afterward with "Select" or via the loop's outputs. Where a variable is indispensable, let the loop run sequentially.

Area: Loops & concurrency

Nested loops

Tip 17: Avoid nested loops

A loop within a loop multiplies the number of actions. With 100 outer and 100 inner items, that is already 10,000 iterations. In addition, concurrency only applies at the top level; inner loops always run sequentially.

Recommendation

Replace the inner loop with "Filter array" or a targeted filter in the query. Where nesting cannot be avoided, move the inner part to a child flow.

Area: Loops & concurrency

Do untilQuick to implement

Tip 18: Do until with clear limits

"Do until" repeats actions until a condition is met. To prevent an infinite loop, every loop has limits: by default, it ends after 60 iterations or after one hour (PT1H). At most, 5,000 iterations are possible.

If a limit is reached, the loop ends even if the condition has not yet been met.

Recommendation

Set the count and timeout to suit the process and check after the loop whether the condition has really been met. Build a delay into wait loops so that new requests are not generated at short intervals.

JSON · example
// Do until in code view: at most 20 iterations or 30 minutes
"limit": {
    "count": 20,
    "timeout": "PT30M"
}

Area: Loops & concurrency

Child flows

Tip 19: Split large flows into child flows

Child flows encapsulate tasks that several flows use. This avoids flows with hundreds of steps, makes testing easier, and keeps the logic in one place. A single flow can contain at most 500 actions.

Parent and child flow must be in the same solution. The child flow needs the "Manually trigger a flow" trigger and ends with "Respond to a Power App or flow" or "Response."

Recommendation

Move self-contained, reusable parts to child flows. Pay attention to connections: if the child flow uses connectors other than Dataverse, assign fixed connections under "Run only users."

Area: Loops & concurrency

Expressions & variables

Compose, robust expressions, and fewer calls per item · 5 tips

ComposeQuick to implement

Tip 20: Compose instead of variables

A variable needs one action for initialization and additional actions to set its value. For values that are calculated once and then only read, "Compose" ("Verfassen" in the German UI) is the leaner choice. A flow can contain at most 250 variables.

The output of "Compose" can be reused in all subsequent actions and is also unproblematic in parallel loops.

Recommendation

Use variables only for values that really change during the flow, for example counters in sequential loops. Store fixed or once-calculated values with "Compose" and access them with outputs().

Expression · example
// Compose "Cutoff_date": calculate once
formatDateTime(addDays(utcNow(), -30), 'yyyy-MM-dd')

// Reuse in later actions
outputs('Cutoff_date')

Area: Expressions & variables

Empty resultsQuick to implement

Tip 21: Catch empty results early

If a query returns no matches, the flow still works through all subsequent steps. Actions that expect a value from the result then fail with an error that is not really an error.

Recommendation

Check directly after the query whether there are matches, and otherwise end the flow with "Terminate" and the status "Succeeded." This saves actions and keeps the run history clear.

Expression · example
// Condition: continue only if there are matches
greater(length(body('Filter_open_orders')), 0)

// Alternative: true if the result is empty
empty(body('Filter_open_orders'))

Area: Expressions & variables

Null-safe expressionsQuick to implement

Tip 22: Protect expressions against empty values

If a field is missing from the data or is empty, an expression that accesses nested values without checking fails with an error. Such errors often only become apparent in operation, when a record is incomplete.

Recommendation

Use the question mark operator ?[...] for null-safe field access and provide a fallback value with coalesce(). This keeps the flow running in a controlled way even with incomplete data.

Expression · example
// Empty string instead of null if the field is missing or empty
coalesce(triggerBody()?['Comment'], '')

// Null-safe access to nested values
triggerBody()?['Customer']?['Name']

Area: Expressions & variables

Lookup

Tip 23: Look up data in the flow instead of querying per item

If the flow needs additional master data for each item, for example the name for a customer number, it often queries the data source again in every iteration. This generates many connector calls and increases the risk of throttling.

Recommendation

Load the master data once before the loop and then find the matching entry with "Filter array" in the data already loaded. This significantly reduces the number of requests to the data source.

Area: Expressions & variables

Readability

Tip 24: Keep expressions readable

Expressions are powerful, but long and deeply nested expressions are hard to check and maintain. A single expression may be at most 8,192 characters long.

Recommendation

Break complex calculations down into several "Compose" steps with meaningful names. This costs a few additional actions but makes intermediate results and errors immediately visible in the run history.

Area: Expressions & variables

Error handling & retries

Try-catch-finally, Configure run after, result(), retries, and timeouts · 6 tips

Try-catch-finally

Tip 25: Try-catch-finally with scopes

Without error handling, a flow stops at the first error, and often nobody finds out in time. With scopes, you recreate the proven pattern from programming: the "Try" scope contains the actual actions, "Catch" runs only if "Try" fails, and "Finally" runs regardless of whether "Try" or "Catch" succeeded.

So that the run still appears as failed in the event of an error, record the error in the "Catch" scope, for example in a variable. After "Finally," a condition then ends the flow with the "Terminate" action, the status "Failed," and a meaningful message. A "Terminate" directly in "Catch" would end the run immediately and skip "Finally."

Recommendation

Structure every production flow into the Try, Catch, and Finally scopes and set "Configure run after" appropriately for Catch and Finally. This way, the flow responds to errors in a controlled manner and reports them reliably.

Area: Error handling & retries

Configure run after

Tip 26: Set "Configure run after" options carefully

By default, every action runs only if the previous one succeeded. With "Configure run after," you specify whether an action should also run after an error, a timeout, or a skipped action. At least one status must remain selected.

Recommendation

Set "Catch" to "Has failed" and "Has timed out," and "Finally" to all four statuses. After every change, check with a test whether the paths work as intended.

Area: Error handling & retries

result()

Tip 27: Read error details with result()

In the "Catch" scope, you initially know only that something failed in "Try." The result() function returns the results of all actions at the top level of a scope, each with name, status, inputs, and outputs.

Actions deeper in the scope, for example within conditions or Switch, are not included in this result.

Recommendation

Filter result() with "Filter array" for the status "Failed" and include the name and error message of the failed action in your notification or error log.

Expression · example
// Filter array "Filter_errors", field From
result('Try')

// Condition in advanced mode
@equals(item()?['status'], 'Failed')

// Name of the first failed action
first(body('Filter_errors'))?['name']

Area: Error handling & retries

Link to the run

Tip 28: Error messages with a link to the run

An error message only helps if it leads quickly to the cause. With the workflow() function, the flow knows its environment, its own ID, and the ID of the current run, and can build a direct link to the run from them.

Recommendation

In the "Catch" scope, send a message by email or Teams with the flow name, the failed action, the error message, and the link to the run. With one click, the team can open the point where the flow failed.

Expression · example
concat(
    'https://make.powerautomate.com/environments/',
    workflow()?['tags']?['environmentName'],
    '/flows/',
    workflow()?['tags']?['logicAppName'],
    '/runs/',
    workflow()?['run']?['name']
)

Area: Error handling & retries

Retry policy

Tip 29: Choose retry policies deliberately

Many errors are temporary, for example brief network problems or throttling. Actions that support automatic retries therefore repeat failed calls according to a default policy. How often and at what intervals depends on the performance profile.

In the action's settings, you can change the retry policy: default, none, fixed, or exponential intervals with up to 90 retries. Microsoft recommends exponential intervals because they spread the retries over a longer period.

Recommendation

Use an exponential policy for calls to sensitive systems and turn off retries for actions that must not be executed twice. Remember that every retry counts as a request.

JSON · example
// Action settings in code view
"retryPolicy": {
    "type": "exponential",
    "count": 4,
    "interval": "PT10S",
    "minimumInterval": "PT5S",
    "maximumInterval": "PT1H"
}

Area: Error handling & retries

Timeout

Tip 30: Set timeouts for actions

Synchronous outgoing requests end after 120 seconds. Asynchronous actions, such as approvals, on the other hand, can wait up to 30 days. Without its own timeout, a flow may then be stuck in one step for weeks.

In an action's settings, you set the timeout in ISO 8601 format, for example PT1H for one hour or P3D for three days.

Recommendation

For approvals and other waiting actions, set a timeout that fits the business process, and handle the timeout via "Configure run after" with "Has timed out."

Area: Error handling & retries

Limits, licenses & throttling

Request limits, performance profiles, throttling, run duration, and sizes · 5 tips

Request limits

Tip 31: Know the request limits per license

Every action in a flow counts as a Power Platform request, whether it is a connector action, an HTTP call, or a simple action such as "Initialize variable" or "Compose." Failed actions, retries, and additional pages loaded through pagination count as well.

The limits apply per 24 hours and depend on the license: 6,000 requests with a Microsoft 365 license and 40,000 with Power Automate Premium (as of October 2026). There is currently a transition period in which Microsoft applies the limits per flow instead of per person.

Recommendation

In the Power Platform admin center, identify flows that generate large numbers of requests and reduce their number of actions using the tips in this guide. For very active flows, a Process license may be an option (see tip 32).

Area: Limits, licenses & throttling

Performance profile

Tip 32: Consider the flow's performance profile

The license determines not only the request limits but also the performance profile of a flow. Flows owned by people with a Microsoft 365 license run in the "Low" profile, Power Automate Premium corresponds to "Medium," and the Process license to "High." This determines, for example, the maximum number of items in loops and pagination, throughput limits, and the default retry policy.

If the person who owns a flow leaves the company, it falls back to the "Low" profile. Instant flows use the limits of the person who starts them; automated and scheduled flows use the limits of the person who owns them.

Recommendation

Do not let business-critical flows run under personal accounts with a basic license. For high-volume flows, a Process license can make sense. It assigns the flow its own capacity of 250,000 requests per 24 hours.

Area: Limits, licenses & throttling

Throttling

Tip 33: Plan for connector throttling

In addition to the daily request limits, connectors have their own throttling limits that apply regardless of the available capacity. On top of that come service protection limits of target systems such as Dataverse. If a limit is exceeded, actions are delayed or fail.

If a flow is throttled continuously, the platform turns it off after 14 days.

Recommendation

Spread the load over time, reduce calls with filters, batches, and "Filter array," and limit concurrency. You can find a connector's throttling limits in its reference on Microsoft Learn.

Area: Limits, licenses & throttling

Run duration and retention

Tip 34: Know run duration and retention

A single run may last at most 30 days. If it waits longer, for example for an approval, it is terminated. The run history is also retained for only 30 days, counted from the start of a run.

For flows in solutions, Dataverse also stores the run history in the FlowRun table, by default for 28 days. The platform turns off flows whose triggers or actions fail continuously after 14 days. Flows without trigger activity can be turned off after 90 days, except for flows owned by people with a premium or capacity license.

Recommendation

Plan long waiting times as separate flows, for example with a status column and a new trigger, instead of letting a run wait for weeks. Save run data you need for longer in a log table of your own.

Area: Limits, licenses & throttling

Message size

Tip 35: Keep an eye on message size and files

A single message in Power Automate may be at most 100 MB, or up to 1 GB with chunking. In addition, the platform limits data throughput per five minutes and per 24 hours.

Large files, Base64 content, and extensive JSON responses slow down every step that reads or passes them on, and they also end up in the run history.

Recommendation

Wherever possible, pass only references such as IDs or paths between actions instead of complete file contents, and load content only where it is needed.

Area: Limits, licenses & throttling

Maintainability & ALM

Solutions, connection references, environment variables, naming, and versions · 6 tips

Solutions

Tip 36: Create flows in solutions

Flows in solutions can be moved as a package between development, test, and production environments. Only they support connection references, environment variables, version history, and run history in Dataverse, which is analyzed by tools such as the automation center.

Outside of solutions, one person can own at most 600 flows; in solutions, there is no such limit.

Recommendation

As a rule, create new flows in a solution. Change flows only in the development environment and bring them to test and production as a managed solution.

Area: Maintainability & ALM

Connection references

Tip 37: Use connection references

In flows outside of solutions, every action is tied directly to a connection. If the connection changes, every affected action must be adjusted. Connection references separate the flow from the specific connection.

When importing into another environment, you map the references to the connections there. Parent and child flows in the same solution can use the same connection reference.

Recommendation

Use one clearly named connection reference per connector and purpose, and link it in test and production to a service account's connections instead of personal connections.

Area: Maintainability & ALM

Environment variables

Tip 38: Environment variables instead of fixed values

SharePoint site addresses, list names, email recipients, or thresholds differ between development, test, and production. If they are hard-coded, the flow must be edited at every move.

Environment variables hold these values, which you supply when importing the solution. For passwords and keys, the "Secret" type references Azure Key Vault. Changed values can take up to an hour to reach all flows.

Recommendation

Move all values that differ by environment into environment variables. Store sensitive values as a secret in Azure Key Vault, not in plain text in the flow.

Area: Maintainability & ALM

Naming and notesQuick to implement

Tip 39: Give actions meaningful names and comments

Names such as "Condition 3" or "Apply to each 2" say nothing about an action's purpose. Whoever maintains the flow later has to open every step first to understand it. The name also appears in expressions such as body() and in error messages.

A name may be up to 80 characters long. Notes on actions explain why a step is built the way it is, similar to comments in code.

Recommendation

Name each action after its purpose, for example "Get open orders," and define a naming convention for the team. It is best to name actions right when you create them, before other steps reference them.

Area: Maintainability & ALM

Flow checkerQuick to implement

Tip 40: Use Flow checker

Flow checker in the designer shows errors and warnings, identifies the affected steps, and links to guidance on fixing them. It opens automatically when you save a flow with errors or warnings.

Recommendation

Open Flow checker before publishing and fix warnings as well as errors. Then test the flow again.

Area: Maintainability & ALM

Version history

Tip 41: Use version history and copies

For flows in solutions, the new designer saves drafts and published versions. Via the version history, you restore an earlier version, which then becomes the latest draft. Drafts are kept for six months, published versions for twelve months.

There is no version history for flows outside of solutions.

Recommendation

Save larger changes as a draft first and publish after testing. For flows outside of solutions, create a copy or export the flow before major rework.

Area: Maintainability & ALM

Security & operations

Tests, secure data, owners, service accounts, data policies, and monitoring · 9 tips

Testing

Tip 42: Test with test data and static results

Do not test flows with real data in production. The designer offers manual tests and automatic tests with a recently used trigger or by repeating an earlier test run.

With static results, an action returns predefined test data without actually being executed. This lets you simulate error cases or skip long steps without putting load on a target system.

Recommendation

Keep your own test data ready in the test environment that also covers special cases such as empty fields, very long texts, and large volumes. Specifically test the error path of your Catch scopes as well.

Area: Security & operations

Secure inputs and outputsQuick to implement

Tip 43: Hide sensitive data in the run history

The run history shows the inputs and outputs of every action. Anyone allowed to edit the flow can therefore also see passwords, tokens, or personal data that pass through the flow.

Recommendation

Turn on "Secure inputs" and "Secure outputs" in the settings of the affected actions. The values then no longer appear in the run history, and the action shows a lock icon.

Area: Security & operations

Owners and co-owners

Tip 44: Assign co-owners

If a flow belongs to only one person, nobody else can change it or fix errors when that person is away. If they leave the company, actions with their connections may fail.

Co-owners can view the run history, edit the flow, update connections, and add further owners. Instead of individuals, you can also add a group, and for SharePoint flows, a list.

Recommendation

Add at least one other person, or preferably a group, as a co-owner for every production flow. Review ownership regularly, for example monthly or quarterly.

Area: Security & operations

Run-only users

Tip 45: Share instant flows with run-only permissions

Anyone who only needs to start a flow does not need editing rights. Run-only users can trigger a flow but cannot view or edit its definition. This works for instant flows with a manual trigger, for example a button or a selected item.

For each connection, you specify whether the person starting the flow provides it themselves or whether the flow uses an embedded connection.

Recommendation

Share instant flows only with run-only permissions. Let the person starting the flow provide any connections used to access their own data, so that each person operates only with their own permissions.

Area: Security & operations

Service accounts and service principal

Tip 46: Decouple critical flows from individuals

If business-critical flows run under personal accounts, they depend on that person's license, role, and continued employment. A dedicated service account with a suitable license decouples the flow from this.

A service principal goes one step further: an application in Microsoft Entra ID becomes the owner of the flow as an application user. For premium connectors, the flow then needs a Process license, for example.

Recommendation

Have production flows owned by a service account or a service principal, and use its connections in the connection references. Microsoft recommends that service principals own all flows in production environments.

Area: Security & operations

Data loss prevention (DLP) policies

Tip 47: Consider DLP policies early

With data loss prevention (DLP) policies, administrators determine which connectors may be used together in a flow. For this purpose, connectors are classified into the groups "Business," "Non-business," and "Blocked." Connectors from different groups cannot be combined in one flow, and blocked ones cannot be used at all.

Recommendation

Before building, clarify which DLP policies apply in the target environment. For production flows, a dedicated environment with a clearly defined policy is recommended, so that later changes to the default environment do not unexpectedly hold up the flow.

Area: Security & operations

Monitoring

Tip 48: Monitor flows regularly

Flows run in the background, so problems are often noticed late. The run history shows every single run, and a flow's analytics summarize runs, error rates, and average run times for the last 30 days.

The automation center brings together runs, errors, and recommendations for flows in solutions. In the Power Platform admin center, administrators see analytics for the entire environment. Application Insights can be connected for custom alerts.

Recommendation

Look at the error rates and run times of your most important flows regularly, not only when someone complains. Increasing run times are often the first sign of growing data volumes or throttling.

Area: Security & operations

Error notification

Tip 49: Send reliable error notifications

Power Automate sends failure notifications by email, but only for certain errors with a known cause, for example expired connections or throttling. After such a notification, no further ones follow for the same flow for 28 days. In addition, there is a weekly digest.

General errors in actions do not trigger a notification of their own. Anyone who relies solely on these emails will therefore miss many errors.

Recommendation

Build your own error notification into the "Catch" scope of every production flow (see tip 28). Send it to a team mailbox or a Teams channel instead of to individuals.

Area: Security & operations

General

Tip 50: Make flow maintenance an ongoing task

Fewer outages, lower request consumption, faster processes, easier maintenance, more security, and future-proofing: an optimized flow pays off on many levels. Data volumes, licenses, and the platform itself change continuously, and with them the requirements for your flows.

Recommendation

See maintaining your flows not as a one-time task, but as an integral part of operations and an investment in reliable processes. Check important flows regularly against the tips in this guide.

Area: Security & operations

04Tip 50 in detail

Why optimization always pays off.

Optimizing cloud flows is part of running them well, rather than a one-time cleanup: it reduces request consumption and costs, prevents silent failures, and builds trust in automation across the company.

  • Fewer outages

    Clean error handling, retry policies, and timeouts make flows robust. Errors are detected, reported, and can be fixed quickly.

  • Lower consumption

    Fewer runs and actions mean fewer requests against the license limits and less frequent need for additional capacity. In environments with pay-as-you-go billing, costs also fall with fewer billable runs.

  • Faster processes

    Targeted queries, data operations instead of loops, and concurrency shorten the run time. Results are available sooner, and callers wait less.

  • Easier maintenance

    Meaningful names, notes, scopes, and child flows make flows understandable. Changes and troubleshooting are faster, even for people who did not build the flow.

  • More security

    Secure inputs and outputs, service accounts, and clear ownership protect data and prevent flows from depending on individual accounts.

  • Future-proofing

    Flows in solutions with connection references and environment variables can be moved cleanly between environments and adapted to new requirements.

  • Strategic approach

    Optimization is not just technology, but an investment in reliable processes and in the automation of the entire company.

05Template for businesses

For approvals, there is a toolkit.

With the Approval Toolkit for Power Automate, your team plans, builds, and tests approval processes. It includes ten building blocks with detailed instructions covering single-stage approval, escalation, delegation, and logging; four scenarios; an Excel planner with a test log; and a template for process descriptions and acceptance.

  • Standard connectors only, premium license required only in Managed Environments
  • Deadlines, reminders, escalation, and delegation
  • License for the whole company and any number of its own processes

06Flow analysis

I take a look at your flows.

Are your cloud flows too slow, do they keep failing, or do they hit limits? I am happy to analyze your existing flows and create a comprehensive report with specific recommendations. You can then carry out the optimization yourself, or I can take it over for you.

  1. Free initial consultation

    We clarify which flows are involved, where the problems are, and what access I need for the analysis.

  2. Analysis of the flows

    I examine the triggers, actions, loops, expressions, error handling, and data queries of your flows, using the run history, analytics, and Flow checker, among other tools.

  3. Comprehensive analysis

    You receive a report that shows what is slowing down your flows or making them fragile, why, and what needs to be done, with recommendations ordered by impact and effort.

  4. Optimization

    You implement the recommendations yourself with your team, or I carry out the optimization for you.

You handle the optimization

The analysis is structured so that your team or your service provider can implement the optimization step by step.

I handle the optimization for you

I implement the recommendations directly in your flows, document the changes clearly, and test them.

07Questions and answers

Frequently asked questions

Why is my Power Automate flow slow?
Common causes are loops over large amounts of data, nested loops, queries without filters, a separate query for each item, and throttling due to too many calls. The run history shows how long each action takes. Filter queries, the "Filter array" and "Select" actions instead of loops, and "Apply to each" concurrency often help.
What are trigger conditions?
Trigger conditions are expressions in the trigger settings. The flow starts only if they are met. Unlike a condition inside the flow, they prevent the run entirely; no entry appears in the run history, and you save runs and requests.
How many requests may a flow execute?
That depends on the license. With a Microsoft 365 license, it is 6,000 Power Platform requests per 24 hours, with Power Automate Premium 40,000, and with a Process license 250,000 (as of October 2026). In the current transition period, Microsoft applies the limits per flow. Every action counts, including retries and additional pages loaded.
How do I catch errors in a flow?
With the try-catch-finally pattern: the actual actions are in a "Try" scope, and a "Catch" scope runs via "Configure run after" only on errors or timeouts. There, you use result() to retrieve details of the failed action, send a notification with a link to the run, and record the error. Only after the "Finally" scope does "Terminate" end the run with the status "Failed," so that it appears as failed.
May I share the guide?
Yes, please share a link to this page. The content is protected by copyright. For any other use, for example in your own training materials, just contact me.

Want your flows to run faster? Let's talk about it.

In a free, no-obligation initial consultation via Microsoft Teams, we clarify where your flows waste time and requests and whether an analysis with a report is the right next step.