Acumatica · Customization

PXGraph vs PXGraphExtension — Choosing the Right Tool

When to create a brand-new PXGraph in Acumatica, and when to extend an existing one — with a decision framework that keeps your customization upgrade-safe.

John Kihiu12 min read

"Do I extend the existing graph or write a new one?" comes up on almost every scoping call, and it's a more consequential decision than it first looks — get it wrong and you either end up fighting an unrelated screen's existing behavior, or you duplicate a pile of logic Acumatica already gives you for free. Here's the decision framework I actually use, with the reasoning behind each branch rather than just a rule of thumb.

The question underneath the question

Every version of this decision reduces to one thing: does the requirement modify behavior on a screen/workflow that should continue existing as Acumatica shipped it, or does it need a genuinely new workflow that happens to reuse some existing data? The first is a PXGraphExtension<T>. The second is a new PXGraph, possibly reusing existing DACs and even existing graph's data views by composition, but with its own identity, its own screen, its own lifecycle.

Reach for PXGraphExtension when...

C#
// Right call: adding a rule to an existing, still-relevant screen
public class SOOrderEntry_CreditCheck : PXGraphExtension<SOOrderEntry>
{
    public static bool IsActive() => true;
    protected virtual void _(Events.RowPersisting<SOOrder> e) { /* ... */ }
}

Reach for a new PXGraph when...

C#
// Right call: a purpose-built bulk tool, not a modification
// of Sales Order Entry's own behavior
public class BulkPriceOverrideEntry : PXGraph<BulkPriceOverrideEntry>
{
    public PXSelect<SOOrder,
        Where<SOOrder.status, Equal<SOOrderStatus.open>>> CandidateOrders;
    // its own action set, its own screen, its own sitemap entry
}

A new graph doesn't mean duplicating logic — reuse via composition or shared methods

Choosing a new graph doesn't mean re-writing validation logic the base graph already has. Acumatica graphs can instantiate and delegate to other graphs (PXGraph.CreateInstance<T>()), and shared business logic is often better factored into a plain static or instance helper class both graphs call, rather than duplicated. The new-graph decision is about screen/workflow identity, not a license to copy-paste validation rules that already exist elsewhere.

The anti-pattern I actually see most often: extending an unrelated screen because it's "close enough"

The mistake I catch most in code review isn't picking a new graph when an extension would do — it's the opposite: cramming a genuinely different workflow into an extension of an existing graph because it saves the work of setting up a new screen. The result is a screen that behaves inconsistently depending on entry point, with event handlers that only make sense for one of the two use cases silently firing for both. If you're writing if (isSpecialWorkflow) { ... } else { ... } branches inside a graph extension's event handlers, that's usually a sign the special workflow wanted to be its own graph from the start.

A quick test that resolves most ambiguous cases

Ask: "if I described this new workflow to an end user in one sentence, would they say it's the same screen with an extra button, or a different tool"? If it's "the same screen, one more thing it does," extend. If it's "a different tool that happens to touch the same data," write a new graph. This framing catches the cases that feel technically ambiguous but are actually clear once you think about it from the user's mental model rather than the code's.

Wrapping up

PXGraphExtension for modifying behavior on a screen that should keep being that screen; a new PXGraph for a genuinely distinct workflow, even one built heavily on the same underlying data. Reuse logic through composition and shared helpers regardless of which you choose — the decision is about screen and workflow identity, not a reason to duplicate validation rules. And watch for the more common real-world mistake: forcing a distinct workflow into an existing graph's extension because it's the path of least short-term effort.

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.