DevOps · Devops

Acumatica Feature Flags Implementation

Acumatica has no built-in feature flag system, but publishing a customization is all-or-nothing. Here is how I use a simple Usr-prefixed flag field and setup screen to decouple deploying customization code from turning its behavior on.

John Kihiu12 min read

There is no official Acumatica "feature flag" feature — no toggle screen shipped by the platform, no SDK for it. What I mean by feature flags here is a discipline I apply myself when building customizations: a way to get code into production without committing to turning its behavior on for everyone at the same moment. It matters in Acumatica specifically because of how publishing works.

Why Acumatica customizations need this more than most platforms

When you publish a customization project, it goes live as a unit. There's no native concept of a canary release or a gradual rollout of a customization package — the project is either published or it isn't, and once it's published, every screen and every piece of graph extension logic in it is live for every user with access. That's fine for a bug fix. It's a problem for anything bigger: a new validation rule on Sales Orders, a changed default, a new required field — the kind of change you'd rather verify against one company or one branch before every user in every subsidiary hits it. Without something in between, "the code is deployed" and "the behavior is active for everyone" are the same event. A flag field is how you separate them.

The mechanism: a Usr-prefixed field the code checks

The pattern is plain: add a custom boolean or selector field — something like UsrNewPricingLogicEnabled — on a setup DAC you control, expose it on a setup screen (or an existing configuration screen if one fits), and have the graph extension check that field before running the new logic. Nothing exotic; it's the same conditional-visibility and conditional-branch tooling you already use for everything else in Acumatica, pointed at a switch instead of a business rule.

C# · GRAPH EXTENSION
public class SOOrderEntry_PricingExt : PXGraphExtension
{
    protected virtual void _(Events.RowUpdated e)
    {
        var row = (SOOrder)e.Row;
        if (row == null) return;

        var setup = SelectFrom.View.Select(Base);
        bool newPricingEnabled = setup?.UsrNewPricingLogicEnabled == true;

        if (newPricingEnabled)
        {
            ApplyNewPricingLogic(row);
        }
        else
        {
            ApplyLegacyPricingLogic(row);
        }
    }
}

The setup DAC is a single-row (or per-branch) table you already know how to build — the same shape as any other company-level or branch-level settings screen. There's no separate flag-management product to install; it's a screen you own, sized to exactly the flags you need and no more.

Scoping the flag per tenant or per branch

Where this earns its keep is multi-tenant and multi-branch deployments. If the setup DAC is keyed by CompanyID (or scoped to a specific tenant in a multi-tenant instance), you can publish the customization across the whole environment during a maintenance window, but leave the flag off everywhere except the one company or branch you're validating against. Confirm the new behavior against real data for that tenant, then flip the flag on for the next one, and the next, instead of every tenant getting the new behavior the instant the DLL lands. This is not Acumatica giving you tenant-isolated feature rollout — it's you building a settings table that happens to respect the same CompanyID boundaries the rest of the ERP already enforces.

The flag is not a substitute for a real rollback plan

A flag field only helps if the old code path is still there to fall back to. If your "new logic" replaces the old logic outright instead of branching around it, turning the flag off does nothing — you've already deleted your rollback. Keep both paths live until the flag has been on in production long enough that you're comfortable deleting the old one.

The cheaper version: conditional field or action visibility

Not every rollout needs a branching graph handler. If the change is "this new field or button shouldn't be visible to everyone yet," PXUIField's Visible property (or a PXDefault/PXUIField pair driven off the same setup field, or off a role check) is a poor-man's flag that costs a few lines. You're not toggling logic, just whether a control appears — useful when the risk is UI confusion rather than a behavior change that could corrupt data. I reach for this before I reach for a full setup-DAC-and-branch approach; it covers a surprising number of "not ready for everyone yet" requests on its own.

When to remove the flag

A flag that outlives its rollout is just dead conditional logic that the next developer has to reverse-engineer. Once a behavior has been on for every company or branch for a normal business cycle and nobody's asked to roll it back, delete the old code path, delete the flag field, and delete the setup screen control if nothing else uses it. The discipline isn't just adding the switch — it's taking it back out once the decision it was protecting has actually been made.

Wrapping up

Acumatica doesn't ship a feature flag system, and pretending otherwise just confuses the next developer who goes looking for one. What it does have is an all-or-nothing publish model, which is exactly why a flag is worth building yourself: a Usr-prefixed field on a setup DAC, checked by the graph extension before the new logic runs, scoped by CompanyID or branch if you need staged rollout across tenants. It turns "deployed" and "turned on" into two separate decisions you control instead of one publish click that commits you to both at once.

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.