I got an email from a viewer, telling me how he used xRec to fix a specific issue. In this video I ask a simple question: Are you still using xRec? (and I show what xRec is about).

In this video, Erik explores a classic AL construct — xRec — after receiving an email from a viewer named Michael who suggested it as a topic. What starts as a simple explainer turns into a thoughtful reflection on whether xRec is still relevant in modern Business Central development, and why Erik himself has largely stopped using it.
What Is xRec?
The concept of xRec is straightforward: when you retrieve a record from the database (via a GET, a page load, or other means), the system saves a copy of how the record looked at that point. This copy is stored in xRec, which is typed the same as the Rec variable for the table.
Historically, in the old native database, xRec was used for concurrency control. When you performed a MODIFY, the system would compare the current database state with xRec. If another user had changed the record since you retrieved it, you’d get the classic error message: “Another user has changed the definition of this record since it was retrieved.” — a message that has gone through many iterations over the years, none of which were particularly good at explaining what actually went wrong.
The Simple Use Case
The most common use case for xRec is inside OnValidate triggers. The idea is to compare the previous value of a field with the new value to determine if something actually changed, and then conditionally execute business logic — or skip it if nothing is different.
To demonstrate, Erik set up a simple table with three fields and a list page:
The Test Table
table 50121 "Test Table"
{
Caption = 'Test Table';
DataClassification = ToBeClassified;
fields
{
field(1; "code"; Code[20])
{
Caption = 'code';
DataClassification = ToBeClassified;
}
field(2; "Text 1"; Text[200])
{
Caption = 'Text 1';
DataClassification = ToBeClassified;
trigger OnValidate()
begin
if GuiAllowed then
message('x=%1 new=%2 (%3)', xRec."Text 1", Rec."Text 1", CurrFieldNo);
end;
}
field(3; "Text 2"; Text[300])
{
Caption = 'Text 2';
DataClassification = ToBeClassified;
}
}
keys
{
key(PK; "code")
{
Clustered = true;
}
}
}
The Test Page
page 50121 "Test Page"
{
ApplicationArea = All;
Caption = 'Test Page';
PageType = List;
SourceTable = "Test Table";
UsageCategory = Administration;
layout
{
area(content)
{
repeater(General)
{
field("code"; Rec."code")
{
ToolTip = 'Specifies the value of the code field';
ApplicationArea = All;
}
field("Text 1"; Rec."Text 1")
{
ToolTip = 'Specifies the value of the Text 1 field';
ApplicationArea = All;
}
field("Text 2"; Rec."Text 2")
{
ToolTip = 'Specifies the value of the Text 2 field';
ApplicationArea = All;
}
}
}
}
}
In the OnValidate trigger for “Text 1”, the code displays a message showing the old value (xRec."Text 1"), the new value (Rec."Text 1"), and the current field number (CurrFieldNo).
What Happens at Runtime
When you create a new record and type a value into the “Text 1” field, you see:
- x = (blank) — because the field was empty before
- new = (whatever you typed) — the value you just entered
If you then change the value, xRec contains the previous value of the field — i.e., what was there before the validate trigger fired. This is an important nuance: in modern Business Central, xRec in a validate trigger is a copy of Rec before the assignment, not necessarily the unmodified record from the database.
CurrFieldNo: xRec’s Close Companion
CurrFieldNo tells you which field originally triggered the validation. In the example above, when “Text 1” (field number 2) is validated, CurrFieldNo returns 2. While this seems obvious when you’re directly inside the field’s OnValidate trigger, it becomes useful when you’re deeper in a call stack and need to know which field initiated the chain of logic.
The Behavior Varies by Caller
This is where things get tricky. In the early days of NAV, there was only one client — the Windows client. Fields could only be validated in two ways: by the UI or by calling VALIDATE in code. But in the modern world, we have web services, APIs, background sessions, and various other callers.
Microsoft documents the different behaviors in their help pages, and the scenarios include:
- xRec is empty and CurrFieldNo is 0 — when called from certain non-UI contexts
- xRec is the same as Rec — in some programmatic validation scenarios
- xRec contains the copy of Rec before assignment — when called from the UI validate trigger or external code that calls the validate function
This inconsistency is precisely why a lot of old code would wrap xRec-dependent logic in if GuiAllowed then — to ensure that the code only ran when triggered from the UI, where xRec behavior was predictable. But this made the code fragile, not portable, and difficult to test.
Has xRec Become Obsolete in Practice?
Erik makes an interesting observation: he can’t remember the last time he actually used xRec in his own code. To verify this, he checked his GitHub repository containing all the source code from his YouTube videos — not a single instance of xRec. He also looked at large customer projects and found the same pattern: his coding style simply doesn’t rely on it anymore.
The pattern of triggering one-shot business logic from a validate field based on comparing old and new values seems to have fallen out of favor — at least in Erik’s approach. The reliance on xRec often led to code that was:
- Dependent on being triggered from the UI
- Fragile when called from web services or APIs
- Difficult to unit test
- Not resilient or portable
Conclusion
xRec is one of the oldest constructs in AL, and it still exists and works. It’s not deprecated, and there are certainly scenarios where knowing the previous value of a field is useful. However, the inconsistent behavior across different calling contexts — UI, web services, APIs, background sessions — means that code relying heavily on xRec can be brittle and hard to maintain. Erik’s experience suggests that modern AL development patterns have largely moved away from xRec, favoring more explicit and predictable approaches. If you’re still using it extensively, it might be worth reconsidering whether your code would be more robust without it.