Business Central Extensions: How AL Extensions Actually Work
A practical, platform-neutral guide to the extension-only model that runs modern Business Central - what AL extensions are, when to choose a Per-Tenant Extension (PTE) versus an AppSource app versus a DEV build, how the install and upgrade lifecycle works, and why upgrade safety is the long-term cost that decides whether BC customization pays off. Written by a partner that implements both Dynamics 365 and Odoo for SMEs across Canada, the UK, and the US.
What Are Business Central Extensions?
A Business Central extension is an AL-language package that adds or modifies functionality without touching the base application's source code. Since Microsoft moved the product away from C/AL and C/SIDE - completing the shift at Business Central Wave 2 (version 15) - the product is fully extension-based. Even the base application itself ships as an extension, alongside the open-source System Application modules that partners can consume.
Extensions are written in AL (Application Language), Microsoft's only supported language for Business Central development. They use constructs like tableextension, pageextension, and enumextension - plus event subscriptions and interfaces - to extend base objects rather than overwrite them. This extension-only architecture is what lets Microsoft ship twice-yearly major release waves without partners re-merging customizations into the core - the exact problem that made the old C/SIDE base-code modifications so expensive to maintain.
If you are weighing BC against a modular platform like Odoo (where Odoo Studio customizations layer on top of the core in a similar no-touch way), the parallel is real but the mechanics differ: BC enforces a compiled, signed, version-bound package model, while Odoo's customizations sit inside the app's own inheritance chain. Either way, the strategic lesson for SMEs is identical - extend, do not modify the vendor's base code.
How AL Extensions Work
Development happens in Visual Studio Code with the official AL Language extension installed. The AL: Go! command scaffolds a new project against a sandbox tenant, generating the app.json manifest, launch.json, and a sample HelloWorld page - enough to publish to a sandbox on the first run.
An extension's identity lives in app.json: a unique app ID (GUID), a version number, dependencies on other extensions (including the base application and the System Application), and the object ID range assigned to the publisher. Microsoft's documented object ranges reserve 0-49,999 for the Business Central base application - it must never be used in extensions - while 50,000-99,999 is the range for customer and partner customizations (the classic PTE range). Higher reserved ranges are allocated by Microsoft to AppSource publishers, typically in the 70,000,000+ block.
Inside the package, AL enforces a clean structure: one object per .al file, a consistent prefix or suffix naming convention to avoid collisions, namespaces, PascalCase variables, 4-space indentation, and lowercase keywords. Microsoft's CodeCop and AppSourceCop analyzers enforce these conventions at compile time and flag issues before publish - AppSourceCop is mandatory for any app heading to AppSource validation.
Extension Types: PTE vs AppSource vs DEV
Business Central supports three extension scopes, and choosing the right one is one of the most consequential decisions in any BC customization project. Microsoft's developer documentation defines them by scope: Global, Per-Tenant (PTE), and Dev.
Global apps are published by Microsoft or via AppSource and are available across tenants. Per-Tenant Extensions (PTEs) are uploaded directly to a specific environment and exist only there - their metadata and assemblies are not shared across environments, though a PTE can depend on Global apps, other PTEs, or DEV extensions. DEV extensions live only in sandbox environments and are uninstalled when the sandbox is updated or relocated, which is why they are strictly for development and throwaway exploration.
The simplest framing for an SME: if the customization would be valuable to many customers, build an AppSource app; if it is bespoke to one customer's processes, build a PTE; if it is throwaway exploration in a sandbox, use a DEV extension.
| Dimension | Per-Tenant Extension (PTE) | AppSource app |
|---|---|---|
| Audience | A single customer environment | Many customers via AppSource |
| Distribution | Uploaded directly to the tenant | Published and marketed through AppSource |
| Pricing | Negotiated directly between partner and customer | Free, free-trial, or transactable (per-user monthly/yearly) |
| Object ID range | 50,000-99,999 (customer/partner range) | Microsoft-allocated reserved range (typically 70,000,000+) |
| Cross-environment | Not shared - unique per environment | Shared across all installed tenants |
| Go-to-market effort | Low - partner uploads the .app | High - Partner Center plans, entitlements, Microsoft validation |
The AL Extension Development Lifecycle
A typical PTE engagement moves through a predictable loop. The partner scaffolds the project in VS Code, develops against a sandbox, tests, and then publishes the compiled .app file to the customer's production environment via the Extension Management page or, since 2024 release wave 2, through the Business Central admin center.
On first install, an optional Install codeunit (SubType = Install) runs two triggers: OnInstallAppPerDatabase fires once per database, and OnInstallAppPerCompany fires once per company. These triggers seed default data, set up configuration, or migrate entries from a legacy table. Install codeunits run on first install and on reinstall - they do not run on a version upgrade, which is handled by a separate Upgrade codeunit.
- 01Scaffold and develop
Run AL: Go! in VS Code against a sandbox, write table/page/enum extensions and event subscribers, and validate with CodeCop and AppSourceCop analyzers.
- 02Test in sandbox
Publish as a DEV extension to a sandbox, exercise the new behavior, and confirm no regressions against the base objects you extended.
- 03Package the .app
Compile the project to a signed .app file with the correct app ID, version, and assigned object ID range recorded in app.json.
- 04Install or deploy
Upload the .app to the customer's environment via Extension Management or the admin center (PTE), or submit to AppSource for Microsoft validation (Global app).
- 05Maintain and upgrade
Ship new versions with an Upgrade codeunit that migrates data and schema between versions, using upgrade tags to keep each step idempotent.
Upgrade Safety: Why Compatibility Matters
Business Central ships twice-yearly major release waves, and every installed extension must stay compatible with them. If a publisher lets an extension go incompatible and does not ship a compatible version in time, Microsoft can automatically uninstall the extension to keep the tenant operational - typically after a sequence of an incompatible-extension warning during the preview phase, a failed auto-update at the next major update, and a grace period for the publisher to respond.
Version-to-version migration is handled by an Upgrade codeunit (SubType = Upgrade). Microsoft's developer documentation defines its triggers: OnCheckPreconditions (and its PerDatabase/PerCompany variants) to fail fast if the environment is not ready; OnUpgradePerDatabase and OnUpgradePerCompany to perform the actual data and schema migration; and OnValidateUpgrade (with its PerDatabase/PerCompany variants) to assert the result is sound - an error here rolls the upgrade back.
Upgrade tags - recorded in a per-tenant upgrade tag table - are the recommended way to make each migration step idempotent, so a re-run does not double-apply data changes. The operational lesson is simple but easy to underestimate: every extension you install is a long-term maintenance commitment, not a one-time deployment. Either the publisher keeps it compatible with each major release wave, or the customer eventually loses upgrade headroom and risks an forced uninstall.
Managing Extensions: Install, Upload, Uninstall
Administrators manage extensions from the Extension Management page inside Business Central. From there they can install AppSource apps, upload and deploy PTE .app files, and uninstall extensions when no longer needed.
Since 2024 release wave 2, administrators can also manage Per-Tenant Extensions through the Business Central admin center and its API - the same surface already used to manage AppSource apps. This unifies PTE and AppSource operations and gives partners a cleaner remote-management story across environments.
Uninstalling an extension retains its data by default; the extension can be reinstalled later and the data is still there. To purge the data, an admin must explicitly choose to delete it - via clean-mode sync through the Administration Shell, or through the Delete Orphaned Extension Data page in the client. Dependents must be uninstalled first, which protects against accidentally orphaning another extension that relies on the one being removed.
How Flectic Approaches BC Extensions
Flectic implements Business Central (and Odoo) for SMEs across Canada, the UK, and the US. On BC projects we default to the fewest, most disciplined extensions possible - because every extension is a long-term upgrade commitment, and the partners who over-extend are the ones whose customers lose upgrade headroom two release waves later.
Our AI-Assisted Delivery model is designed to deliver up to 3x faster than a traditional partner engagement on suitably scoped work - not unconditionally, and never as a substitute for the prerequisites that actually de-risk a BC project: a clean RapidStart data load, a documented extension inventory, and an upgrade-tag discipline from version one. If your current BC environment has accumulated years of ad-hoc PTEs, an Extension Readiness review is usually the highest-value first step.
Frequently asked questions
What is the difference between a PTE and an AppSource app in Business Central?
A Per-Tenant Extension (PTE) is uploaded directly to one specific customer environment and exists only there, using the 50,000-99,999 object ID range. An AppSource app is published through Microsoft's marketplace, available across tenants, and uses a Microsoft-allocated reserved object ID range (typically 70,000,000+). PTEs are for bespoke, single-customer customizations; AppSource apps are for functionality many customers would pay for.
What is a DEV extension in Business Central?
A DEV extension lives only in a sandbox environment and is used for development and throwaway exploration. It is uninstalled automatically when the sandbox is updated or relocated, so it should never be used for production customizations. PTEs and Global (AppSource) apps are the two scopes that can run in production.
Do Business Central extensions run on version upgrades?
No. Install codeunits (SubType = Install) run OnInstallAppPerDatabase and OnInstallAppPerCompany triggers on first install and reinstall only. A version upgrade is handled by a separate Upgrade codeunit (SubType = Upgrade) with OnCheckPreconditions, OnUpgradePerDatabase/PerCompany, and OnValidateUpgrade triggers, made idempotent with upgrade tags.
Can Microsoft automatically uninstall a Business Central extension?
Yes. If an extension is incompatible with an upcoming major release wave and the publisher does not ship a compatible version within the grace period, Microsoft can automatically uninstall the extension to keep the tenant operational. This is why every extension is a long-term compatibility commitment, not a one-time deployment.
What happens to data when you uninstall a Business Central extension?
Uninstalling an extension retains its data by default - the extension can be reinstalled and the data is still there. To remove the data, an admin must explicitly delete it via clean-mode sync or the Delete Orphaned Extension Data page. Dependents must be uninstalled first, which prevents orphaning another extension that depends on it.
How are Business Central extensions different from Odoo Studio customizations?
Both layer on top of the vendor's base application without modifying core source code, but the mechanics differ. BC extensions are compiled, signed, version-bound AL packages with enforced object ID ranges and a formal install/upgrade codeunit lifecycle. Odoo Studio customizations sit inside Odoo's own inheritance chain and are managed in-app. Flectic implements both and recommends the fewest, most disciplined customizations on either platform.
Planning a Business Central customization or extension project?
Flectic implements Business Central (and Odoo) for SMEs across Canada, the UK, and the US - platform-neutral advice, Success by Design methodology, and AI-Assisted delivery designed to deliver up to 3x faster on suitably scoped work. Book an ERP Readiness Call and we will map your extension scope, object ID strategy, and upgrade-safety plan before any code is written.
Sources
- Business Central object ID ranges: 0-49,999 reserved for the base application (must not be used in extensions); 50,000-99,999 for customer/partner customizations (PTEs); higher ranges allocated to AppSource publishers. — https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-object-ranges (verified 2026-06)
- Business Central defines three extension scopes: Global (AppSource, cross-tenant), Per-Tenant (PTE, single environment), and Dev (sandbox only, removed on update). A PTE can depend on Global apps, other PTEs, or DEV extensions. — https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-extension-types-and-scope (verified 2026-06)
- An Install codeunit has SubType = Install and supports two triggers: OnInstallAppPerDatabase (runs once per database) and OnInstallAppPerCompany (runs for each company), fired on install or reinstall - not on version upgrade. — https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-extension-install-code (verified 2026-06)
- Upgrading extensions is handled by an Upgrade codeunit (SubType = Upgrade) with triggers OnCheckPreconditions, OnUpgradePerDatabase/OnUpgradePerCompany, and OnValidateUpgrade; upgrade tags make migration steps idempotent. — https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-upgrading-extensions (verified 2026-06)
- Since 2024 release wave 2, administrators can manage Per-Tenant Extensions through the Business Central admin center and its API, the same surface used to manage AppSource apps. — https://learn.microsoft.com/en-us/dynamics365/release-plan/2024wave2/smb/dynamics365-business-central/manage-per-tenant-extensions-admin-center (verified 2026-06)
- Uninstalling an extension retains its data by default; deleting data requires explicit clean-mode sync or the Delete Orphaned Extension Data operation; dependent extensions must be uninstalled first. — https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-unpublish-and-uninstall-extension-v2 (verified 2026-06)
- If an extension remains incompatible with a major update after the grace period, Microsoft can automatically uninstall it to keep the tenant operational. — https://community.dynamics.com/forums/thread/details/?threadid=1bcdef51-64b9-f011-bbd2-00224830b09a (verified 2026-06)
- The shift from C/AL and C/SIDE to the extension-only AL model was completed at Business Central Wave 2 (version 15); the base application and System Application now ship as extensions. — https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-extension-object-overview (verified 2026-06)