I failed at future-proofing an App, or did I?

What do you do to future-proof your apps, and do you sleep when at night when Microsoft rolls out new versions of Business Central? In this video I take a look at why one of my apps didn’t work on v21, check it out:

https://youtu.be/cgmk1r5dXrU

In this video, Erik shares a candid story about how one of his AppSource apps broke when testing against Business Central version 21 — despite his best efforts at future-proofing. He walks through what happened, why it happened, and the surprisingly simple fix, while raising important questions about how developers should manage symbol versions and anchoring strategies in AL development.

The Setup: Advanced Cloud Security App

The app in question is the Advanced Cloud Security app from e-focus. This app provides field-level and data-level security in Business Central — allowing administrators to control which users can see which fields, apply filters, and more. It works across any table, whether from Microsoft, customizations, or third-party extensions.

The app is designed to be very generic and broadly compatible. Officially, it supports Business Central version 16 and up (though Erik hints it technically works on version 15 as well). The goal has always been to have a single app that works everywhere — AppSource and on-premises — without maintaining separate branches.

What Broke

When Erik started testing the app against Business Central version 21, it failed to compile. The culprit? An addafter anchor in a Role Center page customization:

The app was using addafter to place content after a group called “Setup and Extensions” in a Role Center. If you’ve watched Erik’s other videos, you’ll know he frequently advises against using addafter or addbefore with anchors that aren’t truly static. In this case, the anchor turned out to be exactly the kind of thing that could change.

Looking at the Business Central source history (via Stefan Maron’s fantastic open-source repo of the base app code), it became clear that the “Setup and Extensions” group was marked as obsolete in version 18 and then removed in version 21. Once the anchor was removed, the addafter had nothing to attach to, and the app broke.

The Fix

The fix was straightforward: replace the addafter targeting a specific (and apparently mutable) group with an addlast targeting a section. The reasoning is simple — if Microsoft were to break entire sections, everything would break, making this a much more stable and future-proof anchor point.

// Before (broke in v21):
addafter(SetupAndExtensions)
{
    // App content here
}

// After (future-proof fix):
addlast(Sections)
{
    // App content here
}

Why the Obsolete Warning Was Missed

This is where the story gets interesting from a build process perspective. Erik deliberately keeps his symbols locked at version 16 — the minimum version the app supports. This is a conscious decision to prevent accidentally using newer APIs or functions that don’t exist in older versions, which would break backward compatibility.

However, this approach has a trade-off: you never see obsolete warnings for things deprecated in later versions. The “Setup and Extensions” group was obsoleted in version 18, but since the app compiles against version 16 symbols, that warning never surfaced. The problem only became visible when the CI/CD pipeline attempted to compile the app against version 21, where the anchor had been fully removed.

The Broader Future-Proofing Dilemma

Erik highlights a real tension in AL development for apps that target multiple versions:

  • Compile against old symbols to ensure backward compatibility — but risk missing obsolete warnings for things that will be removed in future versions.
  • Compile against new symbols to catch deprecation warnings — but risk accidentally using newer APIs that break on older versions.

One potential solution Erik considers is compiling against both — a base set of symbols for the minimum supported version and a fresh set from newer versions to catch deprecation warnings. But this adds complexity to the build process.

How Long Did the Original Code Last?

In fairness to the original implementation, the last time that particular file was changed was back in version 15. That means the code survived roughly three years before it broke — which is actually a pretty good run for future-proofing. The fix was simple and fast, but the fact that it happened at all was a humbling reminder that no anchoring strategy is foolproof.

Key Takeaways

  1. Never use addafter or addbefore with anchors that Microsoft might change. Prefer addlast or addfirst targeting stable structural elements like sections.
  2. Locking symbols to your minimum supported version protects backward compatibility but creates a blind spot for future deprecations. Consider adding a secondary compilation pass against newer symbols to catch obsolete warnings.
  3. Monitor Microsoft’s obsolete tags proactively. Tools like Stefan Maron’s base app source repository are invaluable for tracking what’s being deprecated and removed.
  4. Test your apps against upcoming versions early and often. CI/CD pipelines that compile against the next major version are essential for catching these issues before they reach production.
  5. One app for all targets (AppSource and on-premises) is achievable, but it requires careful management of symbol versions and anchoring strategies.

This is a great example of how even experienced developers can get caught by the interaction between deliberate design decisions (locking symbols to an older version) and Microsoft’s evolving codebase. The question Erik poses to the community is worth considering: how do you balance backward compatibility with future-proofing in your AL build process?