In this video, I investigate the new data types in AL. Lately, I have been thinking about ways to make internal data types smarter and better for my use.

In this video, Erik explores how modern AL data types — particularly JSON objects and arrays — can be used as powerful, flexible in-memory data structures in Business Central, even when you’re not working with JSON at all. He challenges the assumption that JSON data types are only for JSON serialization/deserialization, and demonstrates how they can replace or augment dictionaries and lists to enable more flexible coding patterns.
Thinking Beyond the Old Way
AL has evolved significantly from the C/AL days. We now have dictionaries, lists, XML data types, JSON data types, and more. Yet many developers — Erik included — find themselves stuck in old patterns, not fully leveraging what’s available. In modern languages like C#, Java, or JavaScript, developers routinely use flexible in-memory data structures. The same thinking can and should be applied in AL.
Dictionaries and Generics in AL
AL dictionaries are actually generic in the .NET sense. When you declare a Dictionary of [Text, Text], both the key and value types are enforced. Change the value type to Boolean, and the Add method’s signature updates accordingly:
var
Dict2: Dictionary of [Text, Text];
This is essentially the same concept as generics in .NET — the compiler enforces type safety based on your declaration. That’s pretty powerful for AL.
A Quick Performance Benchmark
To get a sense of performance, Erik sets up a simple benchmark that adds half a million entries to a dictionary:
var
Dict2: Dictionary of [Text, Text];
Start, Stop: Time;
i: Integer;
begin
Start := Time();
for i := 1 to 500000 do
Dict2.Add(Format(i), Format(i));
Stop := Time();
Message('Time Spend %1', Stop - Start);
end;
Running against a local Docker container, this completes in about half a second — very respectable for half a million inserts.
JSON Objects as Flexible Dictionaries
Here’s where things get interesting. In C#, you can use Dictionary<string, object> to store mixed-type values. AL doesn’t have an object type (the Variant type exists but comes with significant penalties and quirks). However, AL does have JsonObject.
If you swap out your dictionary for a JsonObject, the code looks almost identical — and the performance is the same:
var
Dict: JsonObject;
begin
for i := 1 to 500000 do
Dict.Add(Format(i), Format(i));
end;
The Three Phases of JSON
Erik explains that there are three phases when working with JSON:
- Parsing — Reading from a text/string representation (e.g.,
ReadFrom) - In-memory representation — The object as it lives in memory
- Serialization — Writing back out to text (e.g.,
WriteTo)
The key insight is that phase two is just an in-memory data structure. A JsonObject is essentially a dictionary with text keys. You don’t have to be doing anything related to JSON to benefit from using it.
Mixed Data Types — The Real Advantage
The biggest advantage of JsonObject over Dictionary is the ability to store mixed value types. With a standard dictionary, you’re locked into a single value type. With a JsonObject, you can do this:
for i := 1 to 500000 do begin
if i mod 2 = 0 then
Dict.Add(Format(i), Format(i))
else
Dict.Add(Format(i), Today);
end;
This is impossible with Dictionary of [Text, Text], but perfectly valid with JsonObject.
When reading values back out, you use JsonValue, which provides typed accessors — you can retrieve the value as a date, decimal, boolean, text, and more. Internally values are stored as strings, but the JsonValue type handles conversion through its various As* methods and SetValue overloads.
Storing Records in Dictionaries via JSON
A common request when dictionaries first appeared in AL was the ability to store records as values. Unfortunately, you cannot use a Record type in a dictionary — the compiler won’t allow it. But you can use JsonObject as the value type:
var
Dict3: Dictionary of [Code[20], JsonObject];
With a pair of conversion procedures, you can serialize customer records into JSON objects and store them in the dictionary, then deserialize them back when needed:
procedure CustomerToJson(Customer: Record Customer): JsonObject
begin
// Convert customer fields to JSON object
exit;
end;
procedure JsonToCustomer(JCust: JsonObject; var Customer: Record Customer)
begin
// Populate customer record from JSON object
end;
The performance remains excellent since the underlying JSON.NET library (Newtonsoft.Json) — which has been the go-to JSON library for .NET for over 12 years — is highly optimized and battle-tested.
JSON Arrays as Flexible Lists
The same logic applies to lists. AL provides a List of [T] type, but just like dictionaries, the type is locked. A JsonArray serves as a flexible alternative:
var
L1: List of [JsonObject];
L2: JsonArray;
A JsonArray supports operations like IndexOf, Insert, Count, and Clone — not identical to List, but close. And like JsonObject, a JsonArray can hold mixed data types.
You can also create a List of [JsonObject] if you need a list of complex objects — essentially a list of customer records, each represented as a JSON object.
When to Use Dictionary vs. List
Erik offers a clear guideline for choosing between the two:
- Dictionary — Use when you need specific lookups by key. It’s backed by a hash table, making lookups very fast.
- List — Use when you need to iterate through all entries. It’s backed by a linked list, optimized for sequential access.
If you need to iterate through a dictionary, you can get the keys as a list and loop through them, but this is significantly more expensive:
var
L1: List of [Text];
Txt: Text;
begin
L1 := Dict2.Keys();
foreach Txt in L1 do begin
Dict2.Get(Txt, ...); // Extra lookup per entry
end;
end;
First you extract all keys into a list, then for each key you perform a lookup. If you frequently need both random access and iteration, Erik suggests simply maintaining both structures — memory is plentiful on modern systems.
The Complete Source Code
Here’s the full example code Erik walked through, showing all the different data type declarations and usage patterns:
pageextension 50100 CustomerListExt extends "Customer List"
{
trigger OnOpenPage();
var
Dict: JsonObject;
Dict3: Dictionary of [Code[20], JsonObject];
Dict2: Dictionary of [Text, Text];
L1: List of [JsonObject];
L2: JsonArray;
Start, Stop : Time;
i: Integer;
v: JsonValue;
T: JsonToken;
Txt: Text;
Customer: Record Customer;
begin
for i := 1 to 500000 do begin
Dict2.Add(format(i), format(i))
end;
Start := Time();
for i := 1 to 500000 do
Dict.Get(format(i), T);
Stop := Time();
Message('Time Spend %1', Stop - Start);
end;
procedure CustomerToJson(Customer: Record Customer): JsonObject
begin
exit;
end;
procedure JsonToCustomer(JCust: JsonObject; var Customer: Record Customer)
begin
end;
}
Conclusion
The core takeaway from this video is a mindset shift: JSON data types in AL are not just for JSON. They are general-purpose, high-performance, in-memory data structures that offer capabilities beyond what standard dictionaries and lists provide — most notably, the ability to store mixed data types in a single collection.
By thinking of JsonObject as a flexible dictionary and JsonArray as a flexible list, you can write cleaner, more expressive AL code. Erik mentions that he plans to refactor internal structures in his own BCCL library to take advantage of these patterns, replacing complex multi-list setups with simpler JSON-based structures. If you’ve been building AL extensions the “old way,” it’s worth reconsidering whether these modern data types could simplify your solutions.