Acumatica · Customization

UDFs vs Custom DACs in Acumatica — When to Use Which

When to use Acumatica User-Defined Fields, when to declare a custom DAC, and the tradeoffs that determine which path you should take on a real project.

John Kihiu12 min read

User-defined fields — added through the Customization Editor's UDF designer, no C# required — versus a hand-written PXCacheExtension in a Visual Studio project: I get asked which is "correct" often enough that it's worth writing down the actual tradeoffs, because the honest answer is "it depends on what the field needs to do," not "one is always better."

What the UDF designer actually generates

Adding a field through the Customization Editor's User-Defined Fields tool generates, under the hood, essentially the same thing you'd hand-write — a PXCacheExtension with a Usr-prefixed field, backed by attributes chosen from the designer's UI (data type, length, a subset of common attributes like required/default value). It's not a separate mechanism running in parallel with DAC extensions; it's a no-code UI generating the same underlying extension artifact, packaged inside the customization project without you writing or seeing the C#.

That matters for the decision: you're not choosing between two fundamentally different technologies. You're choosing between generating a DAC extension through a form, versus writing one by hand with full control.

Where the UDF designer is genuinely the right call

Where the UDF designer runs out of road

C#
// What a UDF generates under the hood is structurally similar to
// this — but hand-writing it gives you the PersistingCheck control,
// the exact precision, and a place to add real event logic later
// without switching tools mid-project.
public sealed class CustomerExt : PXCacheExtension<Customer>
{
    public static bool IsActive() => true;

    [PXDBString(11, IsUnicode = true)]
    [PXDefault(PersistingCheck = PXPersistingCheck.Nothing)]
    [PXUIField(DisplayName = "KRA PIN")]
    public string UsrKRAPin { get; set; }
    public abstract class usrKRAPin : PX.Data.BQL.BqlString.Field<usrKRAPin> { }
}
A UDF that later needs behavior doesn't have to be thrown away — but plan the transition deliberately

A field that started as a simple UDF and later needs real validation logic can be migrated: a hand-written PXCacheExtension can declare the same field name and take over from the designer-generated one, provided you remove the UDF-designer version cleanly first to avoid a duplicate-field conflict. I've done this migration on client instances several times as requirements grew past what the designer supports. It's a clean path, but it needs a deliberate customization-project change, not an assumption that you can just "add C# on top of" a UDF in place.

The actual decision rule

If the field needs zero custom event logic and will be maintained by whoever's available (developer or admin), use the UDF designer — it's faster, it's self-service, and it's the same underlying mechanism anyway. The moment the field needs a FieldUpdated cascade, cross-field RowPersisting validation, or attribute precision the designer doesn't expose, write the PXCacheExtension by hand in a real Visual Studio project from the start, because retrofitting behavior onto a UDF-generated field later is possible but is friction you can avoid by making the right call up front.

Wrapping up

UDFs and hand-written DAC extensions aren't different technologies — the designer generates the same kind of PXCacheExtension you'd write by hand, through a form instead of code. Use the designer for simple storage fields and self-service scenarios; write the extension by hand the moment real event-driven behavior, precise attribute control, or serious code review and testing matter. And know that migrating from one to the other later is possible, just not something to assume you'll need until you actually do.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.