I have received a lot of requests to show how to deal with blob fields and JSON objects. In this video, I walk through the process of blob to JSON and JSON to blob, check it out:

In this video, Erik tackles a frequently asked question: how to convert between Blob fields and JSON in AL for Business Central. Since JSON only supports primitive data types (null, boolean, numbers, and text strings), binary data stored in Blob fields needs special handling — specifically, Base64 encoding — to be represented in JSON format.
Understanding the Challenge: JSON Data Types
JSON is essentially a subset of JavaScript — specifically, the object declaration piece. Because of this heritage, JSON is limited to four basic data types:
- Null — not particularly useful in Business Central
- Boolean — true and false
- Number — numeric values
- Text (String) — character data
None of these can directly represent an image or any other binary data. So when we need to store a Blob (binary data) inside JSON, we have to convert it to one of these supported types — specifically, a text string using Base64 encoding.
A Quick JSON Primer in AL
Before diving into the conversion, Erik provides a quick refresher on the JSON types available in AL:
- JsonObject — represents a JSON object (curly brackets containing key-value pairs)
- JsonArray — represents a JSON array
- JsonValue — represents a primitive JSON value
- JsonToken — a “chameleon” type that can represent any of the above; useful when you don’t know what type you’re getting back from a
Getcall
When you call Format() on a JsonObject, it returns the JSON as a text string — similar to how ToString() works in C#. And when you retrieve a value from a JSON object using Get, the result comes back as a JsonToken, which you can then test and cast to the appropriate type (object, array, or value).
Blob to JSON (Exporting)
The key to converting a Blob field to JSON is the Base64Convert codeunit. Base64 encoding represents binary data using a limited set of readable ASCII characters. It works by taking 8-bit bytes and re-encoding them using only ~64 safe, printable characters — which means the encoded output is larger than the original binary data, but it’s entirely text-safe and can be embedded in JSON.
Here’s the process Erik walks through:
- Create a JsonObject
- Add simple fields (like a primary key) directly using
Add - For the Blob field, use
CalcFieldsto ensure the Blob data is loaded - Create an InStream on the Blob field
- Pass the InStream to
Base64Convert.ToBase64()to get a text string - Add that Base64 text string to the JSON object
The Add method on JsonObject has 16 overloads supporting many data types (Option, Integer, Decimal, etc.) — but not Blob. That’s why the Base64 intermediary step is necessary.
To download the resulting JSON, Erik uses a TempBlob pattern: write the formatted JSON to a TempBlob via an OutStream, then create an InStream on the TempBlob and call DownloadFromStream.
JSON to Blob (Importing)
The reverse process — taking a JSON file and extracting a Base64-encoded value back into a Blob field — works as follows:
- Upload the file using
UploadIntoStreamto get an InStream - Read the InStream content into a Text variable
- Parse the text into a JsonObject using
ReadFrom - Use
Getto retrieve the Base64-encoded field into a JsonToken - Check that the token is a value, then extract it as text:
Token.AsValue().AsText() - Create an OutStream on the target Blob field
- Call
Base64Convert.FromBase64()with the Base64 text and the OutStream - Modify the record to save the Blob
The key concept with streams: an InStream is for reading data from something, and an OutStream is for writing data to something. When you create an OutStream on a Blob field, anything written to that stream ends up in the Blob.
Bonus: Exposing Blobs as Text in API Pages
The provided source code shows a practical real-world example of this pattern — exposing the “Work Description” Blob field from the Sales Header table as a text field in a custom API page:
page 50105 salesorderapi
{
APIGroup = 'group';
APIPublisher = 'hougaard';
APIVersion = 'v2.0';
ApplicationArea = All;
Caption = 'salesorderapi';
DelayedInsert = true;
EntityName = 'salesorder';
EntitySetName = 'salesorders';
PageType = API;
SourceTable = "Sales Header";
layout
{
area(Content)
{
repeater(General)
{
field(no; Rec."No.")
{
Caption = 'No.';
}
field(postingDate; Rec."Posting Date")
{
Caption = 'Posting Date';
}
field(workDescription; WorkDescription_BlobAsTxt)
{
Caption = 'Work Description';
}
}
}
}
trigger OnAfterGetRecord()
var
InS: InStream;
begin
Rec.CalcFields("Work Description");
Rec."Work Description".CreateInStream(InS);
Ins.Read(WorkDescription_BlobAsTxt);
end;
var
WorkDescription_BlobAsTxt: Text;
}
This API page demonstrates the same core technique in a slightly different context. In the OnAfterGetRecord trigger:
CalcFieldsis called to load the Blob data (Blob fields aren’t loaded automatically — you must explicitly request them)- An InStream is created on the Blob field
- The InStream content is read into a Text variable
Note that in this case, the “Work Description” field already contains text (not binary image data), so it can be read directly into a Text variable without Base64 encoding. If the Blob contained binary data (like an image), you’d need the Base64 conversion step as described earlier.
Summary
The key takeaways for working with Blobs and JSON in AL:
- JSON cannot hold binary data directly — you must encode it as text using Base64
- Blob → JSON: Create an InStream on the Blob, pass it to
Base64Convert.ToBase64()to get a text string, then add that string to your JSON object - JSON → Blob: Extract the Base64 string from the JSON, create an OutStream on the Blob field, and use
Base64Convert.FromBase64()to decode the string into the OutStream - InStreams are for reading; OutStreams are for writing
- Always call
CalcFieldson Blob fields before reading them — they aren’t loaded by default - For Blobs that contain plain text (like Work Description), you can read directly into a Text variable without Base64 encoding