In this video, I show how to create charts inside Business Central. It has become a standard answer in the channel “ Just use PowerBI ” but Microsoft Dynamics 365 Business Central has a powerful charting tool and it’s pretty easy to use.

As usual, the source is available on github.com/hougaard
In this video, Erik demonstrates how to create charts directly within Business Central using AL code — no Power BI required. While Power BI is a great tool and often the default recommendation for data visualization, Business Central has a built-in chart control that can produce attractive, interactive charts with just a few lines of code. Erik walks through the entire process from scratch, building a chart that visualizes customer sales and profit data.
Why Build Charts Without Power BI?
It’s become almost a default answer in the Business Central community: whenever you need to visualize something, use Power BI. And while there’s nothing wrong with external tools, in many cases you simply want to visualize data that already exists inside the application you’re working in. Business Central ships with a built-in chart control that’s surprisingly capable and performant — Erik mentions using it in production at his day job at eFocus for a project management dashboard with hundreds of data points, and it runs snappily.
Setting Up the Page
To get started, you need a page that hosts the chart control. Erik creates a Card page, which gives the chart plenty of space. You could also use a CardPart page type if you wanted to embed the chart into a FactBox area on another page.
The key ingredient is a usercontrol that references Microsoft’s built-in Business Chart add-in:
usercontrol(Chart; "Microsoft.Dynamics.Nav.Client.BusinessChart")
{
ApplicationArea = All;
}
This control comes from Microsoft out of the box — there’s no need to build a custom add-in. When you deploy the page at this point, you’ll get an empty screen, which makes sense since we haven’t fed the chart any data yet.
The Business Chart Buffer
The secret sauce behind the chart is a table called “Business Chart Buffer”. This temporary record acts as the data model for your chart. All the chart configuration — measures, axes, values — flows through this buffer. Here’s the overall pattern:
- Initialize the buffer
- Add measures (the data series you want to display)
- Define the X-axis
- Loop through your data, adding columns and setting values
- Update the chart control
Building the Chart Step by Step
Initialization and Measures
The first step is to initialize the buffer, then add one or more measures. Each measure represents a data series in your chart. The AddMeasure function takes a caption, a value parameter (more on that in a moment), a data type, and a chart type:
Buffer.Initialize();
// Index 0
Buffer.AddMeasure('Sales', 1, Buffer."Data Type"::Decimal, Buffer."Chart Type"::Column);
// Index 1
Buffer.AddMeasure('Profit', 1, Buffer."Data Type"::Decimal, Buffer."Chart Type"::Pie);
A note on the second parameter to AddMeasure: the documentation calls it something like “value index” or “index value,” and it accepts a variant — you can put anything in there. Erik hasn’t been able to figure out what it actually does; it gets stored in the Business Chart Map table but doesn’t appear to be used for anything meaningful. Putting 1 there seems to be the most common convention.
Defining the X-Axis
Next, define what the X-axis represents:
Buffer.SetXAxis('Customer', Buffer."Data Type"::String);
Since we’re showing customer names, the data type is String.
Populating Data
Now loop through customers, calculate their flow fields, and feed the data into the buffer:
if Customer.FindSet(false, false) then
repeat
Customer.CalcFields("Sales (LCY)", "Profit (LCY)");
if Customer."Sales (LCY)" <> 0 then begin
Buffer.AddColumn(Customer.Name);
Buffer.SetValueByIndex(0, i, Customer."Sales (LCY)");
Buffer.SetValueByIndex(1, i, Customer."Profit (LCY)");
i += 1;
end;
until Customer.Next() = 0;
A few important things to note here:
- Filtering out zero-sales customers keeps noise out of the chart.
AddColumnadds a new entry on the X-axis. The naming is a bit confusing because “column” here refers to a data point in the chart, and we also happen to be using the Column chart type (which renders as bars).SetValueByIndextakes three parameters: the measure index, the X-axis index, and the value.
Zero-Based Indexing — A Quirk
Here’s something that catches people off guard: while almost everything in Business Central is 1-based (including the .NET-adopted collections like Dictionaries and Lists in AL), the SetValueByIndex function uses zero-based indexing for both the measure index and the X-axis index. That’s why the counter variable i starts at 0, and the first measure is referenced as index 0, the second as index 1.
Updating the Chart
Finally, push the buffer data to the chart control:
Buffer.Update(CurrPage.Chart);
The Complete Source Code
Here’s the full page object bringing it all together:
page 50132 "Test Chart"
{
PageType = Card;
Caption = 'Test Chart';
UsageCategory = Administration;
ApplicationArea = All;
layout
{
area(Content)
{
usercontrol(Chart; "Microsoft.Dynamics.Nav.Client.BusinessChart")
{
ApplicationArea = All;
trigger DataPointClicked(point: JsonObject)
var
JsonTxt: Text;
begin
point.WriteTo(JsonTxt);
Message('%1', JsonTxt);
end;
trigger AddInReady()
var
Buffer: Record "Business Chart Buffer" temporary;
Customer: Record Customer;
i: Integer;
begin
Buffer.Initialize();
// Index 0
Buffer.AddMeasure('Sales', 1, Buffer."Data Type"::Decimal, Buffer."Chart Type"::Column);
// Index 1
Buffer.AddMeasure('Profit', 1, Buffer."Data Type"::Decimal, Buffer."Chart Type"::Pie);
Buffer.SetXAxis('Customer', Buffer."Data Type"::String);
if Customer.FindSet(false, false) then
repeat
Customer.CalcFields("Sales (LCY)", "Profit (LCY)");
if Customer."Sales (LCY)" <> 0 then begin
Buffer.AddColumn(Customer.Name);
Buffer.SetValueByIndex(0, i, Customer."Sales (LCY)");
Buffer.SetValueByIndex(1, i, Customer."Profit (LCY)");
i += 1;
end;
until Customer.Next() = 0;
Buffer.Update(CurrPage.Chart);
end;
}
}
}
}
Chart Types You Can Use
The "Chart Type" option on the buffer gives you a variety of visualization styles. Each measure can have its own chart type, so you can mix and match within the same chart:
- Column — standard bar chart (yes, “bar” is called “column” here)
- Line — line chart, great for trends
- Pie — classic pie chart
- Doughnut — like a pie chart but with a hole in the middle
- Bubble — bubble chart (though this one can break depending on your data)
- And more…
Erik demonstrates combining Column and Line types for sales and profit respectively — a pattern you’ll see in Microsoft’s own cash flow charts. He also experiments with mixing Column and Doughnut, which overlays the two chart types on top of each other. Not every combination makes visual sense, but the flexibility is there.
Handling Click Events
The chart control exposes three triggers: AddInReady, DataPointClicked, and Refresh. The DataPointClicked trigger fires when a user clicks on a data point and receives a JsonObject containing information about what was clicked:
trigger DataPointClicked(point: JsonObject)
var
JsonTxt: Text;
begin
point.WriteTo(JsonTxt);
Message('%1', JsonTxt);
end;
The JSON payload includes the measure name (e.g., “Sales”), the label of the clicked column (e.g., “Datum Corporation”), and the Y-value (e.g., 335,000). A quick note on JSON direction: when you want to get data out of a JsonObject, you use WriteTo; when you want to put data into one, you use ReadFrom.
In a real-world scenario, Erik recommends building a dictionary behind the scenes that maps column labels to meaningful identifiers like customer numbers, so you can easily react to clicks and navigate to the relevant record.
Summary
Creating charts in Business Central without Power BI is straightforward and requires surprisingly little code. The key components are:
- The Microsoft.Dynamics.Nav.Client.BusinessChart user control for rendering
- The Business Chart Buffer temporary record for defining and populating chart data
- A simple pattern: initialize → add measures → set X-axis → loop and add data → update
Watch out for the zero-based indexing in SetValueByIndex and the slightly confusing naming conventions (columns vs. columns, anyone?), but once you get past those quirks, you have a powerful, high-performance charting capability built right into Business Central. Whether you embed it in a Card page, a CardPart in a FactBox, or anywhere else, it’s a great option for visualizing data without leaving the application.