Acumatica · Customization

CS Attributes — Screen vs DAC in Acumatica

"Should this be a CS attribute or a DAC field?" is a question I get from developers who've been shown one CSAttribute screen in training and never quite understood why it exists.

John Kihiu12 min read

"Should this be a CS attribute or a DAC field?" is a question I get from developers who've been shown one CSAttribute screen in training and never quite understood why it exists as a separate concept from a normal custom field. The short answer: CS attributes (the Attributes screen under Customization, backed by CSAttribute and CSAnswers) solve a different problem than a DAC extension field, and picking the wrong one costs you either flexibility or performance depending on which way you get it wrong.

CS attributes are a generic, per-entity-type key/value store

A CS Attribute (configured on the Attributes screen, entity class CSAttribute) is not a column on any table. It's a row in a shared attributes definition table, associated with an entity class (Inventory Item, Customer, Case, and so on), and its values live in CSAnswers - one row per entity instance per attribute, with the actual value stored generically as a string, decimal, or date column depending on the attribute's declared type. This is EAV (entity-attribute-value) modeling, and it exists specifically because business users configure these through the UI without a developer writing a DAC field and publishing a customization for every new attribute a category needs.

C#
// Reading a CS Attribute value from code - always indirect, through CSAnswers,
// never a strongly-typed property access like a DAC field
var value = PXSelect<CSAnswers,
    Where<CSAnswers.refNoteID, Equal<Required<CSAnswers.refNoteID>>,
    And<CSAnswers.attributeID, Equal<Required<CSAnswers.attributeID>>>>>
    .Select(Base, item.NoteID, "COLOR");

Notice the join is by NoteID again, same as attachments and notes - CS attributes are yet another consumer of that shared per-entity GUID pattern. There is no compiled property, no IntelliSense, no compile-time type safety. You look the value up by attribute ID string, at runtime, every time.

A DAC extension field is a real, strongly-typed column

A field added via PXCacheExtension<T> is an actual SQL column, participates in BQL queries as a first-class field, gets IntelliSense, and can be referenced in Where<> clauses, joins, and reports without any generic lookup indirection:

C#
public sealed class InventoryItemExt : PXCacheExtension<InventoryItem>
{
    public static bool IsActive() => true;

    [PXDBString(30, IsUnicode = true)]
    [PXUIField(DisplayName = "Color")]
    public string UsrColor { get; set; }
    public abstract class usrColor : PX.Data.BQL.BqlString.Field<usrColor> { }
}

// Usable directly in BQL, with full type safety and query-plan efficiency
var redItems = PXSelect<InventoryItem,
    Where<InventoryItemExt.usrColor, Equal<Required<InventoryItemExt.usrColor>>>>
    .Select(Base, "Red");

The actual decision, not the training-slide version

CS Attributes in a WHERE clause do not scale the way developers expect

I've seen a Generic Inquiry filtering on three CS Attributes on a customer entity with tens of thousands of customers grind to a crawl, because each attribute is a separate join against CSAnswers filtered by attribute ID and note ID. A DAC field with an index handles the same filter as a normal column scan. If a "configurable attribute" is going to be a primary filter criterion on a high-volume list, that's a strong signal it should have been a DAC field from the start, not a CS Attribute retrofitted into performance-sensitive code later.

They can coexist on the same entity without conflict

Nothing stops an entity from having both - CS Attributes for the long tail of business-user-configured, rarely-queried metadata, and DAC fields for the handful of values that drive actual logic. On a manufacturing client I worked with, item specifications used CS Attributes extensively (dozens of them, added by the client's own admin over time, never touched by code), while the two or three fields that fed cost rollup calculations were DAC extension fields, because those needed to be fast, typed, and validated in RowPersisting. That split - configuration-heavy and code-light on one side, logic-critical and typed on the other - is the right mental model more often than either extreme.

Wrapping up

CS Attributes are a generic, admin-configurable EAV store good for sparse, business-user-managed metadata that doesn't drive logic or high-volume filtering. DAC extension fields are real, typed, indexable columns for anything that participates in validation, calculation, or performance-sensitive queries. The mistake in both directions is common: CS Attributes pressed into service as filter-heavy report criteria, or a DAC field added for a one-off attribute that a business user will want to reconfigure every quarter. Match the tool to who needs to change the attribute and how the value gets used, not to which one you learned first.

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.