Optimizing Business Central API Performance
DEC 16, 2025
I have worked with Microsoft Dynamics 365 Business Central APIs a lot over the past two years, mostly Query and Page APIs. They are effective tools, but on one integration I hit a real performance wall: a Page API processing 1000+ records with nested parts took around 4 seconds per call.
How Page APIs work
A Page API exposes data through an OData endpoint with automatic CRUD operations. Here's a simplified example:
page 50100 "Sales Line API"
{
PageType = API;
APIPublisher = 'company';
APIGroup = 'warehouse';
APIVersion = 'v1.0';
EntityName = 'line';
EntitySetName = 'lines';
SourceTable = "Sales Lines";
layout
{
area(Content)
{
repeater(Group)
{
field(itemNo; Rec."No.") { }
field(quantity; Rec.Quantity) { }
}
}
}
}
The real power comes when you need related data, that's where parts come in, they let you embed child collections as nested JSON:
page 50101 "Sales Order API"
{
// ... properties
layout
{
area(Content)
{
repeater(Group)
{
field(orderNo; Rec."No.") { }
field(customerName; Rec."Sell-to Customer Name") { }
part(lines; "Sales Line API")
{
EntityName = 'line';
EntitySetName = 'lines';
SubPageLink = "Document No." = field("No.");
}
}
}
}
}
This gives you a nested JSON like this:
{
"orderNo": "SO-001",
"customerName": "Contoso",
"lines": [
{ "itemNo": "ITEM-1", "quantity": 5 },
{ "itemNo": "ITEM-2", "quantity": 3 }
]
}
Where the time goes
When a Page API with parts retrieves data, the platform queries the main source table, then executes separate queries for each record's related parts, serializes everything through the OData stack, and runs page triggers and field validations along the way. With a large dataset, that adds up to thousands of individual database queries for a single API call.
The solution: a Codeunit API
Instead of the Page API, I moved the heavy endpoint to a custom Codeunit API that handles data retrieval directly. That gives you complete control over querying and table joins, your own filtering and sorting logic, a manually built JSON response, and direct control over what actually gets computed.
The results on the same dataset: response time dropped by roughly 80 percent, from about 4 seconds to about 750ms on average, the response payload was halved, and the database did far less work per call.
Trade-offs
A Codeunit API gives up the automatic OData features: built-in CRUD, $filter, $select and friends all have to be implemented by hand if you need them. For most endpoints the Page API convenience wins. But for performance-critical reads over large datasets, the speed difference justifies the extra development effort.