Microsoft is constantly improving the Business Central platform, but even with that massive momentum, there’s a long list of features that the platform is missing, but don’t worry; in many cases, Microsoft implemented the platform features in the base app. Check out the video:

In this video, Erik takes us on an entertaining tour through the Business Central Base App (version 24), poking around in “dark places” to find code units and functionality that arguably don’t belong there. With the introduction of the Business Foundation app in BC24 and the ongoing reorganization of the platform, Erik highlights several examples of misplaced code — from type helpers and error management to memory stream wrappers — and discusses why these things ended up where they did and what it means for the future of the platform.
The Great Reorganization: Base App, System App, and Business Foundation
When Business Central’s codebase was first organized into separate apps, objects were sorted into two main buckets:
- Base App — the ERP-specific functionality: customers, journals, items, ledger entries, accounting, and so on.
- System Application — the more technical, infrastructure-level pieces.
With BC24, Microsoft introduced a third layer: the Business Foundation app, intended to house foundational business concepts (like number series) that aren’t strictly accounting but aren’t purely technical either. Number series was one of the first things Microsoft moved into this new app.
But as Erik demonstrates, there’s still a lot of code sitting in Base App that has no business being there.
Type Helper: Platform Functions in Disguise
The first example Erik digs into is Type Helper — a classic code unit that exists because the AL platform historically couldn’t do things that it arguably should. Type Helper contains functions for:
- Converting date/time values based on different cultures
- Evaluating and formatting strings with localized settings
- Comparing date/time values
- URL encoding and decoding
- HTML encoding, decoding, and escaping data strings
- Bitwise OR operations
Erik points out the absurdity: “If there’s something like bitwise OR — I know it’s not the thing you do most often in an ERP system, but now we work with web services and communicate with external systems — that should be a platform function. But right now it’s sitting in Base App, of all places.”
The VAR Parameter Anti-Pattern
Erik also calls out a specific pet peeve with Type Helper’s implementation. There are functions that clearly take a text and return a text, but the input parameter is also passed as VAR, meaning it modifies your parameter and returns a value. As Erik puts it: “This is really, really bad and annoying.”
Why Can’t It Just Move to System App?
The reason Type Helper can’t simply be relocated is dependency contamination. By searching for “record” references in the code unit, Erik finds at least one function — GetAmountFormatLCYWithUserLocale — that reads from the General Ledger Setup table. That single function, with its dependency on an ERP-specific table, anchors the entire code unit in Base App.
The fix would be to decouple that dependency through an event or some other loosely-coupled mechanism, but until that’s done, the whole code unit stays put.
Error Message Management
Scrolling through the code units, Erik spots another category of misplaced code: Error Message Management, Error Message Handler, and Error Context / Last Error handling. These are very generic, cross-cutting concerns that have nothing to do with ERP functionality. They work mostly with their own tables and could reasonably live in System App or Business Foundation.
Login Management: The Ghost of Codeunit 1
Erik reminds us of the old days when Codeunit 1 was the monolithic entry point for everything. It eventually got split into multiple pieces, and Login Management is one of those remnants. It contains functionality like showing terms and conditions and tracking time usage — things that are platform-level concerns, not ERP application logic. Some of these might be better candidates for Business Foundation than for Base App.
Mail: Business Foundation with ERP Tentacles
Email functionality is another interesting case. Erik argues that emailing is at least a Business Foundation concept, not something that should live in the ERP-specific Base App. But when you look at the dependencies, you find functions that pull email addresses from Contacts — an ERP table. While a lot of the mail code unit has nothing to do with contacts, those few dependency points keep everything anchored in Base App.
“There’s probably a way better method of doing this,” Erik notes. With some refactoring, much of this code could move to Business Foundation.
Page Management: The Magic Glue
In the 700-range code units, Erik highlights Page Management — a code unit that sounds very generic but is actually deeply intertwined with the ERP layer. This code unit exists because the platform’s PAGE.RUN mechanism, when called with page ID zero and a record, uses a table’s default lookup or drilldown page. But for many tables, that’s the wrong page.
Page Management is the “magic glue” that figures out which page to actually open. For example, if you’re working with table 36 (Sales Header), the correct page depends on the document type — it could be a quote, order, invoice, credit memo, blanket order, or return order. The code unit contains large case structures mapping table/filter combinations to specific pages.
Erik explains this exists because “there isn’t a great way for a page to register itself as the default page for a table with a specific filter.” It’s essentially a pseudo-platform function that had to be built in AL because the platform doesn’t support that concept natively.
Memory Stream Wrapper: Erik’s Own Contribution
Perhaps the most amusing example is Memory Stream Wrapper — a code unit that Erik himself submitted to Microsoft around 2018:
“If there’s something that is as far away from accounting as it can be, it’s probably Memory Stream Wrapper.”
This came out of a predecessor to Microsoft’s current open-source contribution initiative. At the time, .NET interop was being removed from the cloud, and Microsoft asked the community if there was anything they needed. Erik was using memory streams, so he submitted this wrapper. The code unit is a clean 67 lines:
“This is code quality of the highest order — because it’s written by yours truly,” Erik jokes.
Along with Memory Stream Wrapper, there’s a Dictionary Wrapper and a Regex Split Wrapper still sitting in Base App, even though newer regex functionality has since been added to System App.
The Demo Project
Erik’s exploration was done using a simple BC24 project. Here’s the app configuration he used:
{
"id": "846ad30f-6dc7-469c-93fa-1a91e6c9dfc4",
"name": "shortcomingsintheplatform",
"publisher": "Default Publisher",
"version": "1.0.0.0",
"platform": "1.0.0.0",
"application": "24.0.0.0",
"idRanges": [
{
"from": 50100,
"to": 50149
}
],
"runtime": "13.0",
"features": [
"NoImplicitWith"
]
}
And a basic page extension to verify the environment:
namespace DefaultPublisher.shortcomingsintheplatform;
using Microsoft.Sales.Customer;
using Microsoft.Inventory.Item;
pageextension 50100 ItemListExt extends "Item Card"
{
trigger OnOpenPage();
begin
Message('App published: Hello world');
end;
}
Why Does This Happen?
Erik is careful to be fair in his assessment. He acknowledges that the same pattern happens everywhere — including in his own work:
“It’s so easy to go, ‘oh, the platform is missing this function.’ But the platform we have at this point in time is super capable. If they stopped adding new features to the platform, it would not prevent me from feeding my kids next year.”
He describes the common dynamic: the app team at Microsoft needs something, they ask the platform team, and the platform team says “we can make that in version 27.” The app team can’t wait, so they build their own little thing. Erik does the same thing in his own projects. It works, but it creates these kinds of misplacements over time.
Conclusion
The ongoing reorganization with Business Foundation is a step in the right direction, but there’s clearly a lot of work still to do. Code units need to be “decontaminated” — those single record-dependent functions that anchor entire utility code units in Base App need to be decoupled through events or other loosely-coupled patterns. Some functionality (like bitwise operations, URL encoding, and date/time culture handling) arguably belongs directly in the AL language or platform, not in any app layer at all.
Whether this cleanup lands in version 25 or later, it’s a fascinating look at how even well-architected systems accumulate technical debt — and how the Business Central team is working to untangle it.