Which AL App Runs First? Trigger Execution Order in Custom Apps (OnPrem)

Guidelines for Partners

In Microsoft Dynamics 365 Business Central (OnPrem), when developing with AL using multiple custom apps, it’s common to run into scenarios where more than one app contains logic inside the same trigger. So the key question is: When multiple custom apps include code in the same trigger, which one runs first?

The short answer is: The app with lower dependency (i.e., higher in the dependency tree) will execute first.

Let’s look at an example of understanding the Dependency Tree:

When App B declares a dependency on App A (via app.json), this means:

  • App B depends on App A
  • App A is considered less dependent
  • So App A will run first, and App B will run after

This rule applies not only to events, but also to code inside standard AL triggers, when those triggers are extended or modified in multiple apps.

But what if we have more than two apps? What happens when multiple apps modify the same object, but there’s no declared dependency between them? Which one runs first? Could it possibly depend on app’s unique ID?

Let’s create two custom apps and call them: Alpha and Beta. In both apps, we’ll create page extension for the “Sales Order” page and modify the “Sell-to Customer No.” field’s “OnValidate” trigger by adding a simple message calls in triggers and corresponding event subscribers, like: “OnAfterValidate”, “OnBeforeValidate”, “OnBeforeValidateEvent”, “OnAfterValidateEvent”.

    layout

    {

        modify(“Sell-to Customer No.”)

        {

            trigger OnAfterValidate()

            begin

                Message(‘APP A – OnAfterValidate’);

            end;

 

            trigger OnBeforeValidate()

            begin

                Message(‘APP A – OnBeforeValidate’);

            end;

        }

    }

 

    [EventSubscriber(ObjectType::Page, Page::”Sales Order”, OnBeforeValidateEvent, “Sell-to Customer No.”, false, false)]

    local procedure P42_OnBeforeValidateEvent_Subscriber()

    begin

        Message(‘APP A – OnBeforeValidate Event’);

    end;

 

    [EventSubscriber(ObjectType::Page, Page::”Sales Order”, OnAfterValidateEvent, “Sell-to Customer No.”, false, false)]

    local procedure P42_OnAfterValidateEvent_Subscriber()

    begin

        Message(‘APP A – OnAfterValidate Event’);

    end;

 

The current dependency tree is as follows:

1. Beta is dependent on Alpha app.

  • Expected code execution order: (1) Alpha, (2) B
  • Actual code execution order: (1) Alpha, (2) B

AL app

 

 

 

 

 

 

Just this once, let’s take a look at the detailed execution flow (after this, we’ll focus only on the “OnBeforeValidate” and “OnAfterValidate” triggers):

Alpha “OnBeforeValidateEvent”, Beta “OnBeforeValidateEvent”,

Alpha “OnBeforeValidate”, Beta “OnBeforeValidate”,

Alpha “OnAfterValidate”, Beta “OnAfterValidate”,

Alpha “OnAfterValidateEvent”, Beta “OnAfterValidateEvent”.

 

Now reverse the Dependency Tree:

2. Alpha is dependent on Beta app.

  • Expected code execution order: (1) Beta, (2) A
  • Actual code execution order: (1) Beta, (2) A

AL app

 

 

 

 

 

 

This clearly shows how the dependency between two apps determines the execution order of code related to the same object. Now let’s add a third custom app, Cobra, with the same messages calls in all the relevant triggers.

The current dependency tree is as follows:

3. Beta, Cobra are dependent on Alpha app.

  • Expected code execution order: (1) Alpha, (2) Beta or C..
    • We know that Alpha app will execute first since it is considered least dependent, but what determines the execution order of the remaining apps?
  • Actual code execution order: (1) Alpha, (2) Cobra, (3) B

AL app

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Let’s now look at another dependency scenario to see how the execution order changes:

4. Alpha, Cobra are dependent on Beta app.

  • Expected code execution order: (1) Beta, (2) Alpha or C..
    • We know that Beta app will execute first since it is considered least dependent, but will the Cobra app execute second again?
  • Actual code execution order: (1) Beta, (2) Alpha, (3) C

AL app

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

This time Alpha app’s code was executed before Cobra’s unlike the previous case. Let’s take a look at the apps’ unique IDs:

  • Alpha – 85a52d3b-c8c4-4b69-9dea-18ebb4c68bcd
  • Beta – e7629da4-2814-4c23-babb-c9067a661c4b
  • Cobra – 87b5c570-df44-4fda-ba6c-42ae19fbe1e1

The IDs are sorted lexicographically (i.e., based on alphabetical and numerical order, like dictionary order) in ascending order: Alpha < Cobra < Beta.

Let’s now try one final combination to test the theory that execution order among equally dependent apps might follow the lexicographical order of their App IDs.

5. Beta, Alpha, are dependent on Cobra app.

  • Expected code execution order: (1) Cobra, (2) Alpha, (3) Beta
    • We know that Cobra app will execute first since it is considered least dependent, if the theory about IDs order is correct, Alpha should run second and Beta third because Alpha’s ID is lower than Beta’s.
  • Actual code execution order: (1) Cobra, (2) Alpha, (3) Beta

AL app

 

 

 

 

 

 

 

 

 

 

 

 

 

 

This confirms the execution order depends on the IDs’ order. But let’s not stop here and add another custom app, Delta, for further testing. Let’s review the IDs and their order once again:

  • Alpha – 85a52d3b-c8c4-4b69-9dea-18ebb4c68bcd
  • Beta – e7629da4-2814-4c23-babb-c9067a661c4b
  • Cobra – 87b5c570-df44-4fda-ba6c-42ae19fbe1e1
  • Delta – 08b01993-7e03-493f-9313-e8b9b8407298

The new order of the app IDs (from smallest to largest) is:  Delta < Alpha < Cobra < Beta.

The current dependency tree is as follows:

6. Beta, Cobra, Delta are dependent on Alpha app.

  • Expected code execution order: (1) Alpha, (2) Delta (3) Cobra, (4) Beta
    • We know that Alpha will execute first since it is considered least dependent, since Delta app has the smallest ID among the dependant, it should execute second, followed by Cobra and Beta in ascending ID order.
  • Actual code execution order: (1) Alpha, (2) Delta (3) Cobra, (4) B

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Let’s continue testing with additional dependency tree setups using custom apps.

The current dependency tree is as follows:

7. Beta is dependent on Alpha app, Cobra, Delta is dependent on Beta app.

  • Expected code execution order: (1) Alpha, (2) Beta (3) Delta, (4) Cobra
    • We know that Alpha will execute first since it is considered least dependent, next is Beta which depends on Alpha (making it the second least dependent app). Among the apps dependent on Beta, Delta has the smaller ID and should execute before C
  • Actual code execution order: (1) Alpha, (2) Beta (3) Delta, (4) C

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The current dependency tree is as follows:

8. Beta, Cobra are dependent on Alpha app, Delta is dependent on Beta app.

  • Expected code execution order: (1) Alpha, (2) Beta or C.
    • We know that Alpha will execute first since it is considered least dependent. Will Beta or Cobra follow as they both depend on Alpha? Will it be Beta as it has dependants, or will it be Cobra as it has smaller ID then Beta? Does Beta’s dependants influence if the app is going to be executed before Cobra’s? We know that Delta should not execute before Beta because it depends on it, so in what order will the smallest ID owner Delta app execute?
  • Actual code execution order: (1) Alpha, (2) Beta, (3) Delta, (4) C

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

There could be two conclusions to this test:

  1. First conclusion is that apps are run by the order of ID (from smallest to biggest). Beta follows root app, as it depends on Alpha and has a dependent app Delta with the smallest ID. Even if Delta has smallest ID, it cannot be executed before Beta because it depends on it, so it can only execute after dependant app did. Cobra, though also dependent on Alpha, has no dependents and have a bigger ID then Delta, so it executes last.
  2. Another conclusion could be that in more complex cases, dependency depth (least dependent apps run first), number of dependents (apps with more dependents may run earlier) with their dependant apps, and app ID order (used to break ties when dependency levels are equal) all influence the execution order.

Let’s do more dependency tree test cases to find out which conclusions aligns better.

The current dependency tree is as follows:

9. Cobra, Delta are dependent on Alpha app, Beta is dependent on Delta app.

  • Expected code execution order: (1) Alpha, (2) Delta or C..
  • Actual code execution order: (1) Alpha, (2) Delta (3) Cobra, (4) B
    • The result shows that the apps were run by the order of IDs from smallest to biggest.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Now reverse the Dependency Tree:

10. Cobra, Delta are dependent on Alpha app, Beta is dependent on Cobra app.

  • Expected code execution order: (1) Alpha, (2) Delta (3) Cobra, (4) B
    • We know that Alpha will execute first since it is considered least dependent. Delta follows, as it depends on Alpha and has the smallest ID. Cobra also dependent on Alpha and has a bigger ID then Delta so it executes third. Beta can only execute at some point after it’s dependant app and it also has the biggest ID, so it executes last.
  • Actual code execution order: (1) Alpha, (2) Delta (3) Cobra, (4) B

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Based on the test results, we can say that apps run in order of their IDs (from smallest to largest), but their dependencies must run first to allow them to execute in lexicographical order.

Let’s find out if this is true if another custom app is added, Echo. Let’s review the IDs and their order once again:

  • Alpha – 85a52d3b-c8c4-4b69-9dea-18ebb4c68bcd
  • Beta – e7629da4-2814-4c23-babb-c9067a661c4b
  • Cobra – 87b5c570-df44-4fda-ba6c-42ae19fbe1e1
  • Delta – 08b01993-7e03-493f-9313-e8b9b8407298
  • Echo – 9a3c2beb-98e2-49e7-b462-906cd4c4f783

The new order of the app IDs (from smallest to largest) is:
Delta < Alpha < Cobra < Echo < Beta.

The current dependency tree is as follows:

11. Beta, Delta, Echo are dependent on Cobra app, Alpha is dependent on Echo app.

  • Expected code execution order: (1) Cobra, (2) Delta, (3) Echo, (4) Alpha, (5) B
    • We know that Cobra will execute first, as it is considered the least dependent. The rest of the apps execute in order of their IDs. Delta has the smallest ID, so it executes second. Alpha has the second smallest ID, but since it depends on Echo, Echo executes third, followed by A Beta has the largest ID, so it executes last.
  • Actual code execution order: (1) Cobra, (2) Delta, (3) Echo, (4) Alpha, (5) Beta

 

 

 

 

 

 

 

 

 

 

 

 

 

The current dependency tree is as follows:

12. Beta, Cobra are dependent on Alpha app, Delta are dependent on Cobra app, Echo are dependent on Beta app.

  • Expected code execution order: (1) Alpha, (2) Cobra, (3) Delta, (4) Beta, (5) Echo
    • We know that Alpha will execute first since it is considered least dependent. The rest of the apps executes by the IDs order. Delta has the smallest ID but it is dependent from Cobra, so Cobra executes second and Delta follows. Echo has the smaller ID then Beta, but it cannot execute before it because Echo depends on Beta app, that’s by Beta executes first and then goes Echo
  • Actual code execution order: (1) Alpha, (2) Cobra, (3) Delta, (4) Beta, (5) Echo

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The current dependency tree is as follows:

13. Echo, Delta are dependent on Alpha app, Cobra is dependent on Echo app, Beta is dependent on Delta app.

  • Expected code execution order: (1) Alpha, (2) Delta, (3) Echo, (4) Cobra, (5) Beta.
    • We know that Alpha will execute first since it is considered least dependent. The rest of the apps executes by the IDs order after their dependencies have executed.
  • Actual code execution order: (1) Alpha, (2) Delta, (3) Echo, (4) Cobra, (5) Beta.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The current dependency tree is as follows:

14. Beta, Echo are dependent on Alpha app, Cobra is dependent on Echo app, Delta is dependent on Cobra app.

  • Expected code execution order: (1) Alpha, (2) Echo, (3) Cobra, (4) Delta, (5) Beta.
    • We know that Alpha will execute first since it is considered least dependent. The rest of the apps executes by the IDs order after their dependencies have executed.
  • Actual code execution order: (1) Alpha, (2) Echo, (3) Cobra, (4) Delta, (5) Beta.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The current dependency tree is as follows:

15. Echo, Delta are dependent on Cobra app, Beta, Alpha are dependent on Delta app.

  • Expected code execution order: (1) Cobra, (2) Delta, (3) Alpha, (4) Echo, (5) Beta.
    • We know that Cobra will execute first since it is considered least dependent. The rest of the apps executes by the IDs order after their dependencies have executed.
  • Actual code execution order: (1) Cobra, (2) Delta, (3) Alpha, (4) Echo, (5) Beta.

 

 

 

 

 

 

 

 

 

 

 

These last test confirms the execution order depends on the IDs’ order.

Based on the tests conducted, we can conclude that when multiple custom apps contain logic within the same trigger in Business Central (OnPrem), the execution order follows a consistent pattern:

  • Execution begins with the root app—the least dependent app.
  • It then proceeds in the order of App IDs, from smallest to largest, following the dependency tree.

In other words, apps run in lexicographical App ID order, but only after their dependencies have executed, allowing for a dependency-respecting execution sequence.

While this behaviour was consistently observed across 15 test cases involving up to 5 apps, it is important to note that this is not officially documented by Microsoft. Therefore, the execution order is not guaranteed and may vary in future versions or differ in SaaS environments. Internally, execution may also be influenced by factors like alphabetical order or metadata loading, which are not reliable for controlling logic flow.

Still, based on the OnPrem tests, the results clearly show that the execution order is based on App ID (from smallest to largest), but only after the app’s dependencies have been processed.