AL Programming for Business Central Customization: Complete Developer Guide [2026]
AL (Application Language) is a modern, strongly-typed programming language purpose-built for Business Central extensions, accessed via free VS Code development tools, structured around objects (tables, pages, codeunits, reports) deployed as either published AppSource extensions (monetized, multi-tenant, Microsoft-validated) or per-tenant extensions (private, deployed to single environments), best suited for organizations with medium-to-complex customization needs that outpace declarative configuration while requiring full source control, automated testing, and ongoing maintenance investments.
AL Language Overview: Purpose-Built for Business Central
AL (Application Language) is Microsoft’s modern programming language specifically designed for extending Business Central. Unlike C/AL (the legacy language used in Dynamics NAV), AL is strongly-typed, object-oriented, and integrates seamlessly with cloud development practices: version control, CI/CD pipelines, automated testing, and collaborative development workflows.
AL runs on the Business Central server runtime and compiles to .app (application) packages deployed to Business Central environments. The language emphasizes simplicity for common customizations (adding fields, modifying pages, creating reports) while remaining powerful enough for complex integrations and industry-specific solutions.
Key principles:
- Modern syntax: C#-like syntax familiar to enterprise developers; minimal learning curve for C#/.NET developers
- Strongly-typed: All variables, functions, and parameters have declared types; compile-time error detection prevents runtime surprises
- Event-driven: Customizations extend BC functionality via events rather than replacing core code; more maintainable as BC releases evolve
- Cloud-first: Designed for Business Central SaaS; supports cloud-native patterns (async, webhooks, REST APIs)
- Modular: Extensions are independent code packages; multiple extensions can coexist without namespace conflicts
Development Environment: VS Code & AL Tools Setup
Core Setup Requirements
Setting up an AL development environment requires minimal infrastructure:
- Visual Studio Code: Free, lightweight editor from Microsoft (download from code.visualstudio.com)
- AL Language Extension: Install from VS Code marketplace; provides syntax highlighting, IntelliSense, debugging
- Business Central environment: Cloud sandbox or on-premises instance where you deploy and test extensions
- Git (optional but recommended): Version control for extension source code
- AL.Compiler.dll: Automatically installed with the AL extension; compiles AL code to .app packages
Project Structure
A typical AL project directory contains:
- app.json: Project metadata (name, version, publisher, target BC version, dependencies)
- .vscode/launch.json: Debugging configuration (connection to BC server, authentication)
- .vscode/settings.json: Language server settings (compiler options, code analysis rules)
- src/ directory: AL source files (.al files) organized by object type (tables, pages, codeunits)
- .gitignore: Exclude .app packages, .symbols, auth credentials
First Extension: HelloWorld
Creating your first extension takes minutes. VS Code provides project templates (File > New Folder, then AL: Create AL Project in the command palette). This generates:
/HelloWorld
app.json
.vscode/
launch.json
settings.json
src/
HelloWorld.al (sample codeunit)
Compile (Ctrl+Shift+B) and deploy to your BC environment. You now have a working AL project that you can extend.
Extension Architecture: Tables, Pages, Codeunits, and Objects
Core Object Types
AL extensions are composed of objects that extend or create functionality:
| Object Type | Purpose | Example |
|---|---|---|
| Table | Define database schema; tables extend BC base tables or create new tables | Extend Customer table to add “Industry Segment” field |
| Page | User interface for entering/viewing data; pages extend BC pages or create new pages | Create new page for custom dashboards |
| Report | Data retrieval & formatting for printing/export | Custom profit/loss report by department |
| Codeunit | Business logic (functions, procedures); no UI | Webhook handler to fetch data from external API |
| Query | Read-only data structure for reporting and APIs | Sales summary by customer and period |
| XML Port | Import/export data to XML format | Integrate with legacy systems via XML feeds |
| Control Add-in | Custom UI components (JavaScript/HTML) | Interactive map visualization on a page |
| Permission Set | Define user roles and access controls | Create “Industry Analyst” role with read-only access |
Table Extension Example: Adding Custom Fields
One of the most common AL tasks is extending BC’s base tables with custom fields. Instead of modifying BC’s standard Customer table directly (not possible in extensions), you create a table extension that adds fields:
tableextension 50000 "Custom Customer" extends Customer
{
fields
{
field(50001; "Industry Segment"; Text[50])
{
DataClassification = CustomerContent;
}
field(50002; "Annual Revenue"; Decimal)
{
DataClassification = CustomerContent;
}
}
}
This extension:
- Adds two new fields to the Customer table (Industry Segment, Annual Revenue)
- Uses field IDs 50001-50002 (custom extensions use ID ranges 50000+)
- Declares DataClassification (required for GDPR compliance)
- Is transparent to BC updates; when MS releases a new version, your extension persists and re-applies
Page Extension Example: Adding Fields to a Standard Page
After extending the Customer table, you want to show the new fields on the customer card. Create a page extension:
pageextension 50000 "Custom Customer Card" extends "Customer Card"
{
layout
{
addafter("Name")
{
field("Industry Segment"; Rec."Industry Segment")
{
ApplicationArea = All;
}
field("Annual Revenue"; Rec."Annual Revenue")
{
ApplicationArea = All;
}
}
}
}
This page extension adds the two custom fields to the standard Customer Card page immediately after the Name field. Users now see and can edit these fields in the UI.
AppSource vs. Per-Tenant Extensions: Distribution Strategy
AppSource Extensions: Published, Multi-Tenant, Monetized
AppSource extensions are published to Microsoft’s AppSource marketplace and available for installation across all BC environments. Characteristics:
- Multi-tenant: One extension package serves multiple customers; designed for isolated data
- Public distribution: Listed on AppSource; discoverable by any BC customer
- Monetization: Can be free, subscription-based, or one-time purchase
- Microsoft validation: Microsoft reviews code for security, performance, and compliance before publishing
- Update management: MS manages deployment of new versions; customers opt-in to updates
- Marketing reach: Discoverability in AppSource marketplace
- Support burden: You maintain support; customer base can be large and distributed
AppSource use cases: ISVs selling solutions to multiple customers, industry-specific features (manufacturing analytics, retail loyalty), marketplace integrations (Amazon, Shopify), niche functionality targeting a market segment.
Per-Tenant Extensions: Private, Single-Tenant, Internal Use
Per-tenant extensions (also called “private” extensions) are deployed directly to a single BC environment and available only to that tenant. Characteristics:
- Single-tenant: Built for and deployed to one customer/company
- Private distribution: Not listed on AppSource; only accessible within your BC environment
- No monetization: Deployed by the customer (or partner on customer’s behalf)
- No Microsoft validation: You are responsible for code quality, security, testing
- Direct deployment: You control when and how updates are deployed
- Implementation focus: Typically customizations for a specific business process or organization
Per-tenant use cases: Internal extensions for a single company, customer-specific customizations deployed by implementation partners, prototypes and proofs-of-concept, industry-specific solutions deployed for select customers.
Comparison: AppSource vs. Per-Tenant
| Aspect | AppSource Extension | Per-Tenant Extension |
|---|---|---|
| Deployment Model | Multi-tenant (1 package, many customers) | Single-tenant (1 package, 1 customer) |
| Distribution | AppSource marketplace (public) | Direct deployment (private) |
| Publishing | Requires MS validation & approval | No validation; immediate deployment |
| Monetization | Free, subscription, one-time, per-user | Not applicable (internal use) |
| Update Control | MS manages deployment; customers opt-in | You control deployment timing |
| Code Isolation | Must isolate customer data in code | Customer data is contained in single environment |
| Complexity | Higher (multi-tenant patterns, data isolation) | Lower (single-tenant logic) |
| Use Case | Reusable solutions for market segment | Specific customizations for one customer |
Common Customization Patterns: Best Practices
Pattern 1: Event-Based Customization
AL emphasizes event-based customization rather than code replacement. Instead of replacing a BC function, you subscribe to events fired by BC and add your logic:
codeunit 50001 "Customer Event Handler"
{
[EventSubscriber(ObjectType::Table, Database::Customer, 'OnBeforeInsertEvent', ', false, false)]
local procedure OnBeforeCustomerInsert(var Rec: Record Customer; RunTrigger: Boolean)
begin
if Rec."Industry Segment" = ' then
Error('Industry Segment is required');
end;
}
This handler subscribes to the “OnBeforeInsertEvent” of the Customer table. When a user inserts a new customer, your code runs first. If Industry Segment is empty, an error is raised. This pattern is maintainable because your code doesn’t override BC code; it runs alongside it.
Pattern 2: Table Extension with Validation
Combine table extension with validation (OnValidate triggers on custom fields):
tableextension 50000 "Custom Customer" extends Customer
{
fields
{
field(50001; "Annual Revenue"; Decimal)
{
DataClassification = CustomerContent;
trigger OnValidate()
begin
if "Annual Revenue" < 0 then
Error('Annual Revenue cannot be negative');
end;
}
}
}
When a user enters Annual Revenue, the OnValidate trigger fires and checks the value. If negative, an error is raised before the record is saved.
Pattern 3: Integration via API / Webhook
AL enables outbound integrations via REST APIs. A codeunit can call external systems:
codeunit 50002 "External API Handler"
{
procedure CallExternalAPI(CustomerNo: Code[20])
var
Client: HttpClient;
Response: HttpResponseMessage;
Url: Text;
begin
Url := 'https://api.example.com/customers/' + CustomerNo;
Client.Get(Url, Response);
if not Response.IsSuccessStatusCode() then
Error('API call failed: %1', Response.HttpStatusCode());
end;
}
This codeunit calls an external API with the customer number. If the API returns an error status, an error is raised in BC.
When to Customize vs. Configure: Making the Right Choice
Before writing AL code, evaluate whether BC’s declarative configuration features can meet your needs:
| Requirement | Configuration Only | Requires AL Development |
|---|---|---|
| Add custom field to table | Extension table field (no logic needed) | Custom field with complex validation |
| Modify standard page layout | Page extension (add/reorder fields) | Custom page with complex interactions |
| Add validation rule | Field property (Min/Max values, Required) | Complex cross-field validation or external API checks |
| Create report | Power BI / Reporting Services (if simple aggregation) | Complex custom report layouts, multi-source data |
| Integrate with external system | Power Automate / Zapier (simple workflows) | Real-time API integration, complex data mapping |
| Enforce business rules | Approval workflows, posting restrictions | Custom algorithms, conditional logic, API-based rules |
| Add menu action | Action on page (if standard logic applies) | Custom action with bespoke processing |
Philosophy: Use configuration first. Configuration changes are faster to implement, easier to maintain, and more resilient to BC updates. Use AL development when configuration is insufficient.
Development Lifecycle: Build, Test, Deploy, Maintain
Phase 1: Development
Write AL code in VS Code. Typical workflow:
- Create a new project folder and extension in VS Code
- Define app.json metadata (name, version, target BC version, dependencies)
- Write AL objects in src/ directory
- Compile locally (Ctrl+Shift+B) to catch syntax errors
- Deploy to a development BC sandbox for testing
Phase 2: Testing
AL supports automated testing with the AL Test Runner framework. Write unit tests alongside your code:
codeunit 50100 "Test Customer Validation"
{
[Test]
procedure TestAnnualRevenueValidation()
var
Customer: Record Customer;
begin
// Arrange
Customer."No." := '10001';
Customer."Annual Revenue" := -100; // Negative value
// Act & Assert
asserterror Customer.Insert();
end;
}
Tests verify that your custom logic works as intended. Run tests before each deployment to catch regressions.
Phase 3: Deployment
Per-tenant extension: Deploy directly to your BC environment using AL deployment commands (VS Code extensions handle this).
AppSource extension: Package your extension (.app file), submit to Microsoft via Partner Center, await validation (typically 5-10 business days), then publish to AppSource.
Phase 4: Maintenance
After deployment, monitor for issues and plan updates. Considerations:
- BC version updates: When BC releases a new wave (2x yearly), test your extension against the new version. Usually no changes needed, but occasionally BC APIs change and require AL updates.
- Dependency management: If your extension depends on other extensions (e.g., Microsoft’s Tax module), ensure compatible versions are installed.
- Performance monitoring: Monitor extension code for performance issues. Use AL’s performance profiler to identify slow queries or loops.
- User feedback: Collect user feedback and prioritize bug fixes and enhancements for future releases.
Business Central + Shopify Integration: Complete Guide [2026]
Complete guide to native Shopify Connector in Business Central. Setup, features, multi-store support, inventory sync, order processing, limitations, and third-party alternatives.
Read MoreC/AL to AL Migration: Moving from Legacy NAV
Businesses transitioning from Dynamics NAV (which uses C/AL) to Business Central must migrate extensions from C/AL to AL. This is a rewrite, not a port.
Key Differences: C/AL vs. AL
| Aspect | C/AL (NAV Legacy) | AL (BC Modern) |
|---|---|---|
| Type System | Weakly-typed (variant-like) | Strongly-typed (C#-like) |
| IDE | NAV Client / Classic IDE | Visual Studio Code |
| Object Structure | Objects in database | Objects as text files (git-friendly) |
| Customization Model | Replace core objects | Extend objects via extensions |
| API Access | Limited (SOAP) | REST APIs, webhooks |
| Testing | Manual testing | Automated test framework |
| Version Control | Custom solutions (difficult) | Git natively (objects are text files) |
Migration approach:
- Audit NAV extensions: Inventory all C/AL customizations in your NAV system
- Assess BC capability: For each customization, evaluate whether BC configuration can replace it (often 40-60% of NAV customizations are configuration in BC)
- Prioritize AL rewrites: Rewrite complex logic that must stay custom in AL. Simpler customizations may be handled by BC configuration.
- Prototype in BC: Build AL prototypes in parallel with BC implementation; don’t wait until cutover
- Train developers: Ensure your development team learns AL syntax and BC patterns; C/AL developers can typically ramp up in 2-4 weeks
AL Development Costs: Infrastructure & Labor Investment
Infrastructure Costs
AL development itself is free, but running a BC environment for development incurs costs:
- Development sandbox: Included with BC subscription (no extra cost)
- Test/staging environment: Optional; costs same as production BC (typically $150-$300/month for small company)
- Third-party tools: Version control (Azure DevOps / GitHub, often free tier sufficient), CI/CD (GitHub Actions, Azure Pipelines)
Total infrastructure: $0-$300/month for a small team.
Labor Costs
AL development labor is typically the larger cost:
- Simple extension (custom field + validation): 20-40 hours (1-2 weeks) = $2K-$5K at typical rates
- Medium extension (5-10 custom objects, integration): 100-200 hours (3-5 weeks) = $10K-$25K
- Complex extension (industry solution, multi-tenant, AppSource-ready): 500+ hours (3-6 months) = $50K-$200K+
- Maintenance & updates (per year): 10-20% of development cost
Cost Optimization
- Use configuration first: BC declarative features (approval workflows, posting restrictions, custom fields without logic) avoid AL development costs
- Buy off-the-shelf solutions: AppSource extensions cost $100-$500/month but can eliminate months of custom development
- Prioritize ruthlessly: Implement only truly business-critical customizations; accept BC’s default behavior for secondary requirements
- Modernize your NAV extensions: Do not port all NAV customizations to BC; many are redundant due to BC’s superior configuration capabilities
Testing AL Extensions: Unit Tests & Integration Tests
AL Test Framework
AL includes a testing framework allowing you to write automated tests:
codeunit 50200 "Test Custom Workflow"
{
[Test]
procedure TestOrderProcessing()
var
SalesHeader: Record "Sales Header";
Result: Boolean;
begin
// Arrange
SalesHeader."Document Type" := SalesHeader."Document Type"::Order;
SalesHeader."No." := '10001';
SalesHeader."Amount" := 1000;
// Act
Result := ProcessCustomOrder(SalesHeader);
// Assert
assertTrue(Result, 'Order processing should succeed');
end;
local procedure ProcessCustomOrder(var SalesHeader: Record "Sales Header"): Boolean
begin
// Custom business logic
exit(SalesHeader."Amount" > 0);
end;
}
Tests follow the Arrange-Act-Assert pattern and are executed within BC context, allowing real database operations during testing.
Best Practices
- Test critical paths: Write tests for business-critical logic (pricing, approval, integration)
- Test edge cases: Negative values, empty strings, boundary conditions
- Automate test runs: Execute tests in CI/CD pipeline before every deployment
- Aim for 70%+ coverage: Not 100%, but test core logic and error paths
Deployment Strategies: Development → Staging → Production
Per-Tenant Deployment
Typical workflow for customer-specific extensions:
- Develop in sandbox: Write and test AL code in a development environment
- Package extension: Compile extension into .app file (automatic in AL Language extension)
- Deploy to staging: Upload .app file to customer’s staging BC environment; verify functionality
- Deploy to production: After staging sign-off, deploy to production BC environment
- Test in production: Run smoke tests in production to confirm successful deployment
Deployment takes minutes; no system downtime required (BC supports extension deployment without restart).
AppSource Deployment
For published extensions:
- Package & test: Compile extension and test thoroughly
- Submit to Partner Center: Upload .app file and metadata to Microsoft Partner Center
- Microsoft validation: Microsoft reviews code, security, and compliance (5-10 business days)
- Publish: Once approved, extension appears in AppSource; customers can install
- Update management: New versions are deployed automatically to customer environments (with customer approval)
Frequently Asked Questions
Can I customize Business Central without AL development?
Absolutely. Business Central supports extensive configuration without code: custom fields, page layouts, approval workflows, posting restrictions, dimensions, cost centers. Start with configuration; use AL only when configuration is insufficient.
Is AL difficult to learn for non-developers?
AL has a steep learning curve for non-technical users. If you do not have in-house developers, hire a Business Central partner or consider buying off-the-shelf extensions instead of custom development.
Can multiple AL extensions coexist in the same Business Central environment?
Yes. Multiple extensions can run simultaneously. However, if two extensions modify the same object or event, test their interaction carefully to avoid conflicts.
How often should I update my AL extensions for new BC releases?
BC releases two major versions per year (spring and fall waves). Most extensions require no changes; test your extension after each BC release. If BC removes or changes an API your extension uses, update your AL code and redeploy.
Can I call external APIs from AL?
Yes. AL supports HTTP client calls via the HttpClient type. You can call REST APIs, receive JSON responses, and process data. Ensure proper error handling and timeout management.
Is AL suitable for building industry-specific solutions (vertical apps)?
Yes. Many ISVs build industry-specific AL extensions and publish them on AppSource (manufacturing, construction, healthcare). AL is feature-rich enough for complex vertical solutions.
What is the learning curve for developers transitioning from C# to AL?
C# developers typically ramp up on AL in 1-2 weeks. Syntax is similar; the main learning is BC’s object model (tables, pages, codeunits, events).
Can I version control my AL extension?
Yes. AL objects are text files (.al extension) stored in your project directory. Commit them to Git like any source code. This enables version control, code review, and collaboration.
What happens to my AL extension when Business Central updates?
Your extension persists. BC extensions run alongside Microsoft’s code; they don’t overwrite BC objects. If BC releases a new version and removes an API your extension uses, you must update your AL code. Otherwise, no changes needed.
How do I handle errors and debugging in AL?
VS Code provides debugging tools: set breakpoints, inspect variables, step through code. AL also supports error handling via error() and asserterror keywords. Log errors using AL’s logging framework (TestLogging API).
Key Takeaways
- AL is modern, cloud-native, and event-driven: Purpose-built for Business Central; familiar to C# developers; enables clean, maintainable customizations.
- Development environment is free and lightweight: VS Code + free AL extension + a BC sandbox are sufficient to build production extensions.
- Choose your distribution model: AppSource for reusable, multi-tenant solutions; per-tenant for customer-specific customizations.
- Extend rather than replace: AL enforces extension-based customization; your code lives alongside BC’s, not on top of it. More maintainable as BC evolves.
- Configure first, develop second: BC’s configuration capabilities are powerful. Use AL only for logic that configuration cannot handle.
- Test your extensions: AL includes a test framework; automated testing reduces bugs and enables safe refactoring.
- Migration from NAV is a rewrite: C/AL extensions do not port directly; rewrite for BC in AL. Often this is an opportunity to eliminate redundant customizations.
- Cost is mostly labor: AL development itself is free; infrastructure costs are modest. Budget for developer time—simple extensions require weeks, complex ones require months.
- Maintenance is ongoing: Plan for annual updates after BC releases and ongoing support for users.
Frequently Asked Questions
Absolutely. Business Central supports extensive configuration without code: custom fields, page layouts, approval workflows, posting restrictions, dimensions, cost centers. Start with configuration; use AL only when configuration is insufficient.
AL has a steep learning curve for non-technical users. If you do not have in-house developers, hire a Business Central partner or consider buying off-the-shelf extensions instead of custom development.
Yes. Multiple extensions can run simultaneously. However, if two extensions modify the same object or event, test their interaction carefully to avoid conflicts.
BC releases two major versions per year (spring and fall waves). Most extensions require no changes; test your extension after each BC release. If BC removes or changes an API your extension uses, update your AL code and redeploy.
Yes. AL supports HTTP client calls via the HttpClient type. You can call REST APIs, receive JSON responses, and process data. Ensure proper error handling and timeout management.
Yes. Many ISVs build industry-specific AL extensions and publish them on AppSource (manufacturing, construction, healthcare). AL is feature-rich enough for complex vertical solutions.
C# developers typically ramp up on AL in 1-2 weeks. Syntax is similar; the main learning is Business Central’s object model (tables, pages, codeunits, events).
Yes. AL objects are text files (.al extension) stored in your project directory. Commit them to Git like any source code. This enables version control, code review, and collaboration.
Related Reading
Business Central Extensions & AppSource: Complete Guide [2026]
Definitive guide to the Dynamics 365 Business Central extension ecosystem. Learn how extensions work, discover top AppSource apps by category, evaluate ISV solutions, and navigate the modern extension landscape.