Flowfields play a central role in Business Central, and a common development request is to react when a flowfield changes, but how do you actually do that? Check out the video:

A common question from both new and experienced Business Central developers is: “How do I trigger business logic when a FlowField changes?” In this video, Erik demonstrates why FlowFields don’t work like regular fields and walks through the correct approach — subscribing to the event that modifies the source data behind the FlowField. The practical example: automatically blocking a customer for invoicing when their balance exceeds their credit limit.
Understanding FlowFields: They’re Not Really Fields
The first thing to understand is that a FlowField is not a stored field — it’s a just-in-time calculation. Nothing is ever written to the database for a FlowField, and no triggers fire when its value “changes.” Every time you open a page, refresh, or call CalcFields, the value is recalculated on the fly from the underlying data.
Take the Balance (LCY) field on the Customer Card as an example. If you look at its definition in the Customer table (table 18), you’ll see something like this:
field(...; "Balance (LCY)"; Decimal)
{
CalcFormula = sum("Cust. Ledger Entry".Amount WHERE("Customer No." = FIELD("No."), ...));
FieldClass = FlowField;
}
This field simply sums up amounts from the Cust. Ledger Entry table. It’s never stored, never triggers validation, and never fires any events. So you can’t subscribe to “when the balance changes” directly.
The Solution: React to the Source Data
Instead of trying to react to the FlowField itself, you need to react to the event that changes the source data. In this case, the balance changes when a customer ledger entry is inserted — and that happens during posting via Codeunit 12 (“Gen. Jnl.-Post Line”). This codeunit has been the heart of posting in Business Central (and Navision before it) for over 30 years.
If you browse the events exposed by Codeunit 12, you’ll find several related to customer ledger entries. The one we want is OnAfterCustLedgEntryInsert — it fires right after a new customer ledger entry is inserted, giving us access to the entry that was just created.
Tip: Finding Events with AL Code Outline
Erik recommends installing the AZ AL Dev Tools / AL Code Outline extension for VS Code. It gives you an excellent tree view of base application symbols, making it far easier to browse tables, codeunits, and their events.
The Implementation
Here’s the complete codeunit that subscribes to the posting event and blocks a customer when their balance exceeds their credit limit:
codeunit 50123 "Test"
{
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Gen. Jnl.-Post Line", 'OnAfterCustLedgEntryInsert', '', true, true)]
local procedure MyProcedure(var CustLedgerEntry: Record "Cust. Ledger Entry")
var
CustRec: Record Customer;
begin
if CustRec.Get(CustLedgerEntry."Customer No.") then begin
CustRec.CalcFields("Balance (LCY)");
if CustRec."Balance (LCY)" > CustRec."Credit Limit (LCY)" then begin
CustRec.Blocked := CustRec.Blocked::Invoice;
CustRec.Modify(true);
end;
end;
end;
}
Step-by-Step Breakdown
- Subscribe to the event: The
[EventSubscriber]attribute hooks intoOnAfterCustLedgEntryInserton Codeunit “Gen. Jnl.-Post Line”. The twotrueparameters are forSkipOnMissingLicenseandSkipOnMissingPermission. - Get the customer record: We use
CustRec.Get()wrapped in anifstatement rather than calling it directly. This is a deliberate defensive pattern — if for some reason a ledger entry references a customer that doesn’t exist, our code won’t be the thing that causes an error. - Calculate the FlowField: We call
CustRec.CalcFields("Balance (LCY)"). Because the customer ledger entry has already been inserted at this point, the calculation will include the new entry — giving us the current, up-to-date balance. - Compare and act: If the balance exceeds the credit limit, we set the customer’s
Blockedfield toInvoiceand modify the record.
Important Caveats
Be Careful with Database Operations in Event Subscribers
Modifying records inside an event subscriber can be dangerous. If the calling code (in Codeunit 12) has already loaded the Customer record and plans to modify it after your event fires, your Modify call could cause their subsequent Modify to fail — because they’d be working with a stale version of the record. Erik inspected the posting code and determined this is safe in this particular case, but it’s something you should always verify.
Watch Out for Performance with Batch Posting
If a process posts 100 entries for the same customer (e.g., from a journal), this event subscriber would fire 100 times — calculating the balance and potentially modifying the customer record on each iteration. For scenarios like that, you should look for a higher-level event in the call stack that fires once for the entire batch, rather than once per entry. The right event depends on the specific process and what you’re trying to achieve.
Testing It
In the video, Erik demonstrates the solution end-to-end:
- Set a customer’s credit limit to $2,000 (the customer already has a balance of ~$1,700 and is not blocked)
- Create a Sales Invoice for a desk at $1,500
- Post the invoice — the debugger hits the breakpoint in the event subscriber
- After
CalcFields, the balance shows ~$3,000 (including sales tax), which exceeds the $2,000 credit limit - The code sets
BlockedtoInvoiceand modifies the customer - Back on the Customer Card, the customer is now blocked — mission accomplished
Summary
You cannot directly trigger business logic when a FlowField changes because FlowFields are never stored and never fire events. Instead, identify the source of the FlowField’s data, find an appropriate event on the table or codeunit that modifies that source data, and subscribe to it. In this example, the Balance (LCY) FlowField sums customer ledger entries, so we subscribe to OnAfterCustLedgEntryInsert in the posting codeunit. Just remember to be defensive in your event subscriber code, be cautious about database modifications that could conflict with the caller, and consider performance implications when the event fires in high-volume batch scenarios.