How-ToAL Development

How to Build Custom Reports in Business Central

A step-by-step guide to building custom AL reports in Business Central using VS Code, including dataset definition, request page, and layout options.

8 min read

Custom reports in Business Central are built as AL objects and deployed as extensions. The Report object defines the dataset, which tables and fields to include, and references a layout file that controls how the output looks. Once deployed to a sandbox or production environment, the report appears in Business Central like any standard report.

This guide walks through creating a simple customer list report from scratch using VS Code and the AL Language extension.


Prerequisites

  1. VS Code installed with the AL Language extension from Microsoft.
  2. An AL project connected to a Business Central sandbox (configured via launch.json).
  3. Access to a Business Central environment where you can publish extensions.
  4. Basic familiarity with AL syntax and the extension publishing workflow.

Report Object Structure

An AL Report object has three main parts:

  • dataset, defines the data source using dataitem and column declarations
  • requestpage, the filter and options page users see before running the report
  • layout, references an RDLC or Word layout file (or uses a generated layout)

A minimal report object looks like this:

report 50100 "Customer List Custom"
{
    UsageCategory = ReportsAndAnalysis;
    ApplicationArea = All;
    Caption = 'Customer List Custom';

    dataset
    {
        dataitem(Customer; Customer)
        {
            column(No; "No.") { }
            column(Name; Name) { }
            column(Balance; "Balance (LCY)") { }
        }
    }

    requestpage
    {
        layout
        {
            area(content)
            {
                group(Options) { }
            }
        }
    }
}

The UsageCategory property controls where the report appears in the Tell Me search. ReportsAndAnalysis places it under the Reports section. The ApplicationArea property controls which users can see it based on their experience tier.


Step 1: Create the Report File

  1. In VS Code, open your AL project folder.
  2. Create a new file named Report50100.CustomerListCustom.al.
  3. Paste the report object above as a starting point.

Use a report ID in the 50000–99999 range for custom reports. IDs below 50000 are reserved for Microsoft.


Step 2: Define the Dataset

The dataitem declaration binds the report to a table. The column declarations expose individual fields.

To add more fields from the Customer table:

dataitem(Customer; Customer)
{
    column(No; "No.") { }
    column(Name; Name) { }
    column(Balance; "Balance (LCY)") { }
    column(CreditLimit; "Credit Limit (LCY)") { }
    column(Country; "Country/Region Code") { }
    column(SalespersonCode; "Salesperson Code") { }
}

Column names on the left are the identifiers used in the layout. The field references on the right must match the actual field names in the table.

To add a related table, nest a second dataitem inside the first:

dataitem(Customer; Customer)
{
    column(No; "No.") { }
    column(Name; Name) { }

    dataitem(SalesHeader; "Sales Header")
    {
        DataItemLink = "Sell-to Customer No." = field("No.");
        column(DocumentNo; "No.") { }
        column(OrderDate; "Order Date") { }
    }
}

The DataItemLink property joins the two tables, similar to a foreign key relationship.


Step 3: Configure the Request Page

The requestpage section defines any options or filters users can set before running the report. For a simple report, you can leave the Options group empty and Business Central will still show the default date and record filters.

To add a custom option, for example, a toggle to show only customers with a balance:

requestpage
{
    layout
    {
        area(content)
        {
            group(Options)
            {
                field(ShowBalanceOnly; ShowBalanceOnly)
                {
                    ApplicationArea = All;
                    Caption = 'Show Customers with Balance Only';
                }
            }
        }
    }

    var
        ShowBalanceOnly: Boolean;
}

Reference the variable in the dataset using a trigger:

dataitem(Customer; Customer)
{
    trigger OnPreDataItem()
    begin
        if ShowBalanceOnly then
            SetFilter("Balance (LCY)", '>0');
    end;
    ...
}

Step 4: Assign a Layout

Business Central supports two layout types for custom reports: RDLC and Word.

For an RDLC layout, reference it in the report object:

rendering
{
    layout(RDLCLayout)
    {
        Type = RDLC;
        LayoutFile = 'src/layouts/CustomerListCustom.rdlc';
    }
}

For a Word layout:

rendering
{
    layout(WordLayout)
    {
        Type = Word;
        LayoutFile = 'src/layouts/CustomerListCustom.docx';
    }
}

If you do not define a layout, Business Central generates a basic grid layout automatically. This is useful for testing the dataset before the layout is ready.

The RDLC layout file is designed in SQL Server Report Builder or Visual Studio. The Word layout is a .docx file with content controls mapped to column names from the dataset.


Step 5: Deploy to Sandbox and Run

  1. Press F5 in VS Code to publish the extension to your connected sandbox.
  2. In Business Central, search for Customer List Custom using Alt + Q.
  3. The report opens on the Request Page, set any filters and select Print or Preview.

If the report does not appear, check that UsageCategory is set to a value other than None and that ApplicationArea is set correctly for your user profile.


Common Mistakes

  • Column name conflicts: Column identifiers in the dataset must be unique within the report. If two dataitems use a field called Name, prefix one of them, for example, CustomerName and ContactName.
  • Wrong field syntax: Field names with special characters or spaces must be quoted: "No.", "Balance (LCY)". Unquoted names cause compile errors.
  • Layout not found: The layout file path in the rendering section is relative to the AL project root. Make sure the file exists at that path before publishing.
  • ID range conflicts: Check your app.json to confirm the ID 50100 is within your extension’s allowed object range.

Next Steps

  • Add a totals row using a dataitem with DataItemTableView set to a filtered view, or use an OnAfterGetRecord trigger to accumulate running totals.
  • Export the report as PDF or Excel from the Request Page using the Send to options.
  • Assign a custom layout per company using Report Layout Selection without modifying the extension.

For managing how reports are scheduled and distributed automatically, see How to Schedule and Automate Reports in Business Central.