Power Apps  

Configuring Concurrent Data Loading in Power Apps Using Concurrent()

Introduction

As Power Apps applications become more complex, they often need to retrieve information from multiple data sources.

For example, an Employee Management application may need to load:

  • Employee details

  • Department information

  • Manager details

  • Leave types

  • Locations

  • Application configuration

A common approach is to load these data sources one after another.

For example:

ClearCollect( colEmployees, Employees ); 
ClearCollect( colDepartments, Departments ); 
ClearCollect( colManagers, Managers ); 
ClearCollect( colLeaveTypes, LeaveTypes );

Although this approach is simple, each operation is executed sequentially.

That means Power Apps may wait for one operation to complete before moving to the next one.

When an application has several independent data-loading operations, this can increase the time required to initialize the app.

This is where the Concurrent () function becomes useful.

What is Concurrent()?

Concurrent() allows multiple formulas to be evaluated at the same time instead of waiting for each formula to finish before starting the next one.

The basic syntax is:

Concurrent( 
Formula1, 
Formula2, 
Formula3 
)

For example:

Concurrent(
    ClearCollect(colEmployees, Employees),
    ClearCollect(colDepartments, Departments),
    ClearCollect(colManagers, Managers),
    ClearCollect(colLeaveTypes, LeaveTypes)
)


Here, the four independent data-loading operations can execute concurrently.

Instead of thinking about the process as:

Employees
    ↓
Departments
    ↓
Managers
    ↓
Leave Types


we can think of it as:

              ┌── Employees
              │
              ├── Departments
Application ──┼── Managers
              │
              └── Leave Types

The goal is to reduce unnecessary waiting between independent operations.

The Practical Scenario

Consider an Employee Leave Management App.

When the application starts, it needs information from four different sources:

Data SourcePurpose
EmployeesEmployee information
DepartmentsDepartment selection
ManagersManager information
LeaveTypesAvailable leave types

A basic implementation might load each source individually.

Sequential approach

ClearCollect(
    colEmployees,
    Employees
);

ClearCollect(
    colDepartments,
    Departments
);

ClearCollect(
    colManagers,
    Managers
);

ClearCollect(
    colLeaveTypes,
    LeaveTypes
);

The application is effectively performing four separate operations in sequence.

If each operation takes some time to complete, the overall loading process can become noticeably slower.

Configuring Concurrent()

If the four operations are independent, they can be placed inside Concurrent().

Concurrent(
    ClearCollect(
        colEmployees,
        Employees
    ),
    
    ClearCollect(
        colDepartments,
        Departments
    ),
    
    ClearCollect(
        colManagers,
        Managers
    ),
    
    ClearCollect(
        colLeaveTypes,
        LeaveTypes
    )
)

Now Power Apps can evaluate these formulas concurrently.

Why does this help?

The application no longer needs to wait for:

Employees → finish

before starting:

Departments → start

Instead, the independent operations can be initiated together.

Where Should Concurrent() Be Configured?

A common place to use Concurrent() is during application initialization.

For example, an application may have startup logic such as:

Set(
    varCurrentUser,
    User()
);

followed by several independent data-loading operations.

The data-loading portion can be structured using:

Concurrent(
    ClearCollect(colEmployees, Employees),
    ClearCollect(colDepartments, Departments),
    ClearCollect(colManagers, Managers),
    ClearCollect(colLeaveTypes, LeaveTypes)
)

However, the exact placement should depend on the application's architecture and whether the operations are actually independent.

The important point is not simply to put every formula inside Concurrent().

The formulas must be suitable for concurrent execution.

The Most Important Rule: Avoid Dependencies

This is the most important concept when using Concurrent().

The formulas inside Concurrent() should generally be independent of one another.

For example, consider:

Concurrent(
    ClearCollect(
        colEmployees,
        Employees
    ),
    
    ClearCollect(
        colDepartments,
        Filter(
            Departments,
            ManagerID in colEmployees.ManagerID
        )
    )
)

This is problematic because the second operation depends on colEmployees.

The application cannot safely assume that colEmployees has been populated before the second formula evaluates.

Better approach

First load the employees:

ClearCollect(
    colEmployees,
    Employees
);

Then use the result:

ClearCollect(
    colDepartments,
    Filter(
        Departments,
        ManagerID in colEmployees.ManagerID
    )
);

Here, the dependency is explicit.

Independent vs Dependent Operations

A simple rule is:

Independent operations

These can often be placed inside Concurrent().

Concurrent(
    ClearCollect(colEmployees, Employees),
    ClearCollect(colDepartments, Departments),
    ClearCollect(colLocations, Locations)
)

Each collection gets its data from a separate source.

Dependent operations

These should generally be handled in sequence.

ClearCollect(
    colEmployees,
    Employees
);

ClearCollect(
    colManagers,
    Filter(
        Managers,
        ManagerID in colEmployees.ManagerID
    )
);

The second operation depends on the result of the first.

Using Concurrent() Without Collections

Concurrent() is not limited to ClearCollect().

It can be used when multiple independent formulas need to be executed.

For example:

Concurrent(
    Set(varEmployeeCount, CountRows(Employees)),
    Set(varDepartmentCount, CountRows(Departments)),
    Set(varLocationCount, CountRows(Locations))
)

The formulas are independent because each calculation operates on a different data source.

Combining Concurrent() with Application Variables

Suppose an application needs to load several configuration values.

Concurrent(
    Set(
        varCompanyName,
        LookUp(
            AppConfiguration,
            Key = "CompanyName"
        ).Value
    ),
    
    Set(
        varSupportEmail,
        LookUp(
            AppConfiguration,
            Key = "SupportEmail"
        ).Value
    ),
    
    Set(
        varDefaultCountry,
        LookUp(
            AppConfiguration,
            Key = "DefaultCountry"
        ).Value
    )
)

These operations can potentially run concurrently because they don't depend on one another.

However, if all three values come from the same configuration table, it may be even better to consider whether the data access itself can be optimized rather than simply adding Concurrent().

Concurrent() and Performance

One of the main reasons developers consider Concurrent() is application performance.

However, it is important to understand what it actually solves.

Concurrent() can reduce the waiting time between independent operations.

It does not automatically fix:

  • Non-delegable queries

  • Large datasets

  • Inefficient Filter() expressions

  • Excessive LookUp() calls

  • Unnecessary collections

  • Poor data-source design

  • Network latency

  • Slow connectors

  • Large amounts of data being transferred

For example, this may still be inefficient:

Concurrent(
    ClearCollect(colEmployees, Employees),
    ClearCollect(colDepartments, Departments),
    ClearCollect(colManagers, Managers),
    ClearCollect(colLocations, Locations)
)

if each collection is loading thousands of unnecessary records.

The better approach may be to reduce the amount of data being retrieved first.

Concurrent() Is Not a Replacement for Delegation

Consider:

ClearCollect(
    colEmployees,
    Filter(
        Employees,
        Department = "IT"
    )
)

If the query is delegable for the selected data source, the filtering can be performed closer to the data source.

But if the formula is non-delegable, Power Apps may only process a limited number of records locally depending on the data source and application settings.

Using:

Concurrent()

does not remove delegation limitations.

Therefore:

First optimize the query. Then consider whether independent queries can be executed concurrently.

Handling Multiple Data Sources

A realistic application might contain:

SharePoint
    ├── Employees
    ├── Departments
    └── LeaveTypes

Dataverse
    └── ApplicationConfiguration

If the application needs independent information from these sources, Concurrent() can be considered.

Example:

Concurrent(
    ClearCollect(
        colEmployees,
        Employees
    ),
    
    ClearCollect(
        colDepartments,
        Departments
    ),
    
    ClearCollect(
        colLeaveTypes,
        LeaveTypes
    ),
    
    ClearCollect(
        colConfiguration,
        ApplicationConfiguration
    )
)

The benefit can be especially useful when multiple independent connector calls are involved.

However, actual performance depends on the connector, network conditions, data volume, query design, and other factors.

Error Handling with Concurrent()

Another important consideration is error handling.

Suppose one operation fails:

Concurrent(
    ClearCollect(colEmployees, Employees),
    ClearCollect(colDepartments, Departments),
    ClearCollect(colManagers, Managers)
)

A production application should consider how failures should be communicated to the user.

For example:

IfError(
    ClearCollect(
        colEmployees,
        Employees
    ),
    Notify(
        "Unable to load employee information.",
        NotificationType.Error
    )
)

This can be combined with independent operations when appropriate.

The important principle is:

Don't assume that concurrent execution means every operation will always succeed.

Production applications should have an appropriate error-handling strategy.

Showing a Loading Indicator

If the application performs several operations during initialization, users should understand that the application is loading information.

A simple pattern is to maintain a loading variable.

For example:

Set(
    varIsLoading,
    true
);

Concurrent(
    ClearCollect(colEmployees, Employees),
    ClearCollect(colDepartments, Departments),
    ClearCollect(colManagers, Managers),
    ClearCollect(colLeaveTypes, LeaveTypes)
);

Set(
    varIsLoading,
    false
);

A loading container can then use:

Visible = varIsLoading

This provides a better user experience because users can see that the application is processing data rather than assuming that it is unresponsive.

Common Mistakes

1. Putting Everything Inside Concurrent()

Using:

Concurrent(
    Formula1,
    Formula2,
    Formula3,
    Formula4,
    Formula5,
    Formula6
)

does not automatically mean the application is optimized.

The formulas need to be independent and appropriate for concurrent execution.

2. Ignoring Data Volume

Loading an entire table into a collection can be expensive.

Instead of:

ClearCollect(
    colEmployees,
    Employees
)

consider whether the application really needs every employee.

For example:

ClearCollect(
    colEmployees,
    Filter(
        Employees,
        Status = "Active"
    )
)

The exact approach should also consider delegation and the capabilities of the data source.

3. Using Collections Everywhere

Concurrent() is sometimes used together with ClearCollect() so frequently that developers start loading every data source into collections.

This is not always necessary.

If a Gallery can directly use:

Employees

there may be no reason to create:

colEmployees

just to display the same data.

Collections should have a clear purpose.

4. Assuming Concurrent() Guarantees a Specific Execution Order

When formulas are concurrent, developers should not build logic that assumes one formula will finish before another.

If Formula B requires Formula A's result, they should generally not be treated as independent operations.

Before vs After

Without Concurrent()

ClearCollect(colEmployees, Employees);

ClearCollect(colDepartments, Departments);

ClearCollect(colManagers, Managers);

ClearCollect(colLeaveTypes, LeaveTypes);

Conceptually:

Start
  ↓
Employees
  ↓
Departments
  ↓
Managers
  ↓
Leave Types
  ↓
Complete

With Concurrent()

Concurrent(
    ClearCollect(colEmployees, Employees),
    ClearCollect(colDepartments, Departments),
    ClearCollect(colManagers, Managers),
    ClearCollect(colLeaveTypes, LeaveTypes)
)

Conceptually:

                 ┌─ Employees ────────┐
                 ├─ Departments ──────┤
Start ───────────┼─ Managers ──────────┼── Complete
                 └─ Leave Types ──────┘

The second approach allows independent operations to be initiated together.

When Should You Use Concurrent()?

Consider using Concurrent() when:

  • Multiple data sources need to be loaded.

  • The operations are independent.

  • The application has multiple startup tasks.

  • Several independent calculations need to be performed.

  • Connector calls can be performed independently.

  • You have identified sequential waiting as a performance concern.

When Should You Avoid It?

Be cautious when:

  • One formula depends on another formula's result.

  • Execution order is important.

  • You are trying to solve a delegation problem.

  • The actual issue is excessive data retrieval.

  • The application is already performing well.

  • The formulas are difficult to understand or maintain after combining them.