If you have spent any time inside Business Central — as a developer, a consultant, or even an advanced end user trying to understand where a number comes from — you have encountered FlowFields. They are one of the most powerful features in the platform. They are also one of the most misunderstood.
This post explains what FlowFields, FlowFilters, and CalcFormulas actually are, how they work under the hood, why they matter for performance, and how to explore them across your BC schema.
What is a FlowField?
A FlowField is a field that does not store data. Its value is calculated on the fly from data in another table (or sometimes the same table) every time it is read. Think of it as a live aggregate — a sum, a count, an average, a lookup — that is always current because it runs at the moment you ask for it.
The classic example is the Balance field on the Customer table. It does not contain a stored number. Instead, it is defined as a FlowField with a CalcFormula that sums the Amount field on the Customer Ledger Entry table, filtered to open entries for that customer. Every time you open a customer card, BC runs that calculation and shows you the live balance.
Other common examples:
- Inventory on the Item table — sums the Quantity field on Item Ledger Entry
- Balance (LCY) on the Vendor table — sums vendor ledger entries
- Outstanding Orders on the Item table — sums quantities from open sales lines
- Qty. on Purch. Order — sums quantities from open purchase lines
If you have ever wondered why certain fields seem to always be up to date without anyone posting anything, FlowFields are the answer.
How a CalcFormula works
Every FlowField has a CalcFormula that defines its calculation. The formula specifies four things:
- The method — Sum, Count, Average, Min, Max, Lookup, or Exist
- The source table — which table to read from
- The source field — which field to aggregate (for Sum, Average, Min, Max) or retrieve (for Lookup)
- The filters — which records in the source table to include
In AL code, a CalcFormula looks like this:
field(59; Balance; Decimal)
{
CalcFormula = sum("Cust. Ledger Entry".Amount
where("Customer No." = field("No."),
"Global Dimension 1 Code" = field("Global Dimension 1 Filter"),
"Global Dimension 2 Code" = field("Global Dimension 2 Filter"),
"Currency Code" = field("Currency Filter")));
FieldClass = FlowField;
}
Reading this: the Balance field sums the Amount column from the Cust. Ledger Entry table, filtered where the Customer No. matches the current record and optionally filtered by dimension and currency FlowFilters.
The important thing to notice is the field(...) references in the filters. These are not hardcoded values — they refer to other fields on the same record. Some of those fields are ordinary fields (like "No."), but some are FlowFilters.
What is a FlowFilter?
A FlowFilter is a special type of field that exists solely to modify FlowField calculations. Like FlowFields, FlowFilters do not store data. They are filters that you can set at runtime to change what a FlowField returns.
On the Customer table, the Date Filter is a FlowFilter. When you set a date range on it, every FlowField that references it in its CalcFormula recalculates using only entries within that date range. Set it to the current fiscal year and suddenly the Balance field shows only this year's balance. Clear it and you get the all-time balance.
Other common FlowFilters:
- Global Dimension 1 Filter / Global Dimension 2 Filter — slice FlowField calculations by dimension values
- Currency Filter — on Customer and Vendor, filters ledger entries by currency code
- Location Filter — on Item, filters inventory calculations by warehouse location
- Date Filter — appears on most master data tables, restricts FlowFields to a date range
FlowFilters are what make the BC statistics pages work. When you open Customer Statistics, the page sets different date ranges on the Date Filter for each column — current month, current year, all time — and the same FlowFields return different values for each.
When do FlowFields actually calculate?
This is where performance enters the picture. A FlowField does not calculate automatically just because it exists on a record. It calculates when one of two things happens:
- You call
CalcFieldsin AL code — this explicitly triggers the calculation - The field appears on a page — BC automatically calls CalcFields for FlowFields that are bound to visible page controls
If you retrieve a record using Get or FindFirst and never call CalcFields, the FlowField value is zero (or blank). This is a common source of bugs for developers who expect FlowFields to always have values.
In AL:
Customer.Get(CustomerNo);
// Customer.Balance is 0 here — not yet calculated
Customer.CalcFields(Balance);
// Now Customer.Balance has the real value
When you query data through an API or external tool, FlowFields behave differently depending on how you request them. Standard BC API pages typically call CalcFields for you. OData queries on raw tables may not. This is why FlowField columns sometimes appear blank in external tools — the calculation was never triggered.
The performance cost
Every FlowField calculation is a SQL query. When BC calculates the Balance field on a Customer record, it runs something like SELECT SUM(Amount) FROM [Cust_ Ledger Entry] WHERE [Customer No_] = @custNo. That is one query, for one field, on one record.
Now imagine loading a list page with 50 customers, each showing Balance, Balance Due, and Outstanding Orders. That is 50 × 3 = 150 SQL queries just to render the list. If the ledger entry table has millions of rows and the indexes are not ideal, you will feel it.
This is why:
- FlowFields should have supporting indexes — the filters in the CalcFormula need to match a key on the source table. If they do not, BC does a table scan for every calculation.
- Do not include FlowFields in queries unless you need them — if you are pulling Customer data for an export and you do not need the balance, exclude the FlowField columns. Each one you include adds a SQL aggregation per record.
- CalcFields is not free — calling it in a loop over thousands of records can be expensive. If you need aggregated data for a report, consider querying the source table directly rather than calculating FlowFields record by record.
In XPT Data Explorer, FlowFields are flagged with a yellow ⚡ FLOW badge in the field list. When you select FlowFields for a query, the performance gate shows you how many are included and warns you about the per-record cost. This makes it easy to see which fields are FlowFields before you run a query, and to make an informed decision about whether to include them.
How to explore FlowFields in your schema
Understanding which fields on a table are FlowFields — and what they calculate from — is one of the most common tasks for anyone working with BC data. Here are practical ways to explore them:
In XPT Data Explorer
Open any table in the schema browser and look at the Class column. Fields marked FlowField have their value calculated, not stored. Fields marked FlowFilter are the runtime filters that modify those calculations. Normal fields show Normal.
The field cross-reference feature ("Where Used") is particularly useful here. Expand a FlowField and you can see which tables and fields feed into it. This is how you trace where a number comes from without reading AL source code.
The static schema reference is also useful for quick lookups. Every table page lists all fields with their class, so you can bookmark the tables you work with most and check field types at a glance. Try Customer #18 or Item #27 to see FlowFields on the most common master data tables.
In AL code
If you have access to the AL source, search for FieldClass = FlowField to find all FlowField declarations. The CalcFormula immediately above it tells you what it calculates. In VS Code with the AL Language extension, you can Ctrl+click through to the source table.
In the BC web client
On any page, you can use the page inspector (Ctrl+Alt+F1) to see field details. The Expression property shows the CalcFormula for FlowFields. This works without developer access — anyone with a BC login can use it.
Common patterns to watch for
Once you know what FlowFields are, you start noticing patterns across the BC schema:
Master tables aggregate from ledger entries. Customer, Vendor, Item, Bank Account, Fixed Asset — all of these have FlowFields that sum, count, or look up values from their corresponding ledger entry tables. The master record is the anchor; the ledger entries are the transactions.
Document tables aggregate from lines. Sales Header has FlowFields that sum amounts from Sales Line. Purchase Header does the same from Purchase Line. The header knows its totals because FlowFields calculate them from the lines, not because someone stored them.
Setup tables use Exist FlowFields. Some FlowFields do not sum or count — they just check whether a related record exists. This is common in setup and configuration tables where the presence of a record in another table determines a flag or status.
Dimension filters appear everywhere. Global Dimension 1 Filter and Global Dimension 2 Filter are FlowFilters on almost every table that has financial FlowFields. They thread through from the master data tables to the ledger entry tables, allowing any FlowField to be sliced by dimension without storing dimension-specific totals.
Why this matters for data projects
If you are working on a data migration, an integration, or a report, understanding FlowFields changes how you approach the work:
- Do not try to migrate FlowField values. They do not store data. If you are mapping fields between systems, skip any FlowField — it will recalculate from the underlying data.
- If a FlowField shows the wrong value, the problem is in the source table. The FlowField is just a window onto the data. Fix the entries, not the field.
- If a FlowField is slow, check the CalcFormula filters against the source table keys. The most common performance issue is a CalcFormula whose filter fields do not match an index on the source table.
- When building reports, decide early whether to use FlowFields or query the source directly. For a small dataset, FlowFields are convenient. For thousands of records, querying the ledger entries with your own aggregation is faster.
FlowFields, FlowFilters, and CalcFormulas are foundational to how Business Central works. Once you understand them, the BC data model stops feeling like a black box. Numbers have traceable origins, performance issues have clear causes, and the schema starts making sense as a coherent design rather than a random collection of tables.
If you want to explore FlowFields across your own BC environment, XPT Data Explorer is free to use with the Cronus demo data — no signup needed. Every field shows its class, type, and relations. It is the fastest way to understand what is going on inside any BC table.