DevOps · Customization

Acumatica Customization Upgrade Survival Guide

How to make sure your Acumatica customization survives the next version upgrade — the habits, the patterns, the things to avoid, and the test plan that catches breakage before users do.

John Kihiu12 min read

The customization that breaks on upgrade is almost never the one that did something clever. It is the one that reached past the extension boundary — modified a base file directly, depended on a private method, replaced a screen wholesale — and then met a release that moved the thing it depended on. Surviving an Acumatica upgrade is mostly about staying inside the seams the platform guarantees, and knowing where those seams are. This is the checklist and the reasoning behind it.

What actually breaks on upgrade

Three things account for most upgrade pain. First, direct edits to base artifacts — a modified stock screen (ASPX) or a base DAC change — because the new release ships its own version and your change either loses or conflicts. Second, code bound to internal implementation details: calling a non-virtual base method, reading a base field by a name that got refactored, or relying on event ordering that changed. Third, custom SQL and reports built against base table columns that were renamed or restructured. Everything in this guide is about avoiding those three.

Stay inside the extension model

The platform gives you two clean seams: PXCacheExtension for adding fields and PXGraphExtension for adding behavior. Used properly, the base code is untouched and the next release patches it under you. The failure is customizing base logic by copying it. If you find yourself pasting a base method into your extension to tweak three lines, stop — override it and delegate.

C# · OVERRIDE, DON'T COPY
public class SOOrderEntryExt : PXGraphExtension<SOOrderEntry>
{
    public delegate void PersistDelegate();

    // Adds behavior around Persist without owning the base logic,
    // so a base fix in the next release still flows through baseMethod().
    [PXOverride]
    public void Persist(PersistDelegate baseMethod)
    {
        StampFulfilmentRegion();
        baseMethod();
    }

    private void StampFulfilmentRegion() { /* your rule only */ }
}
The Usr prefix is a survival mechanism, not a style rule

Custom fields on stock DACs must start with Usr. It is how the platform keeps your columns distinct from base columns across upgrades — without it, a future release that adds a field of the same name collides with yours and the upgrade breaks.

Keep the project in Git, unpacked

You cannot review or diff a customization ZIP. Export the project once, unzip it into source control, and commit the individual files — the metadata, the code, the per-screen deltas. This is what makes an upgrade tractable: when you move to a new release you can see, file by file, which of your changes still apply, and a screen customization conflict shows up as a real diff instead of a mystery.

Test against the target build before you commit to it

Never upgrade production first. Stand up a copy on the new Acumatica build, restore a recent production database, publish your customization onto it, and let it recompile. The recompile alone catches a large class of breakage — a base method whose signature changed will simply fail to compile against your override. What compiles but misbehaves is caught by the smoke test: open every customized screen, run every customized process once, and reconcile one document end to end.

The recompile is your first regression test

Because Acumatica compiles extension code against the target instance at publish time, publishing onto the new build is itself a check. A green publish rules out the signature-level breakage; a red one points you straight at the base method that moved.

Watch the fragile surfaces

Some things are inherently more upgrade-fragile than a clean graph extension. Replaced (rather than extended) screens, customizations that depend on a specific report template, generic inquiries joined onto columns that a release restructures, and any hand-written SQL in a customization or integration. Keep an inventory of these — they are the surfaces to re-check on every upgrade, and often the ones worth rebuilding as proper extensions so they stop being a recurring cost.

Customization typeUpgrade riskHow to de-risk
Cache extension (Usr fields)LowPrefix correctly; nothing else needed
Graph extension with [PXOverride]Low–mediumDelegate to base; recompile on target
Replaced stock screenHighRebuild as an extension of the base screen
Custom SQL / raw reportsHighMove to BQL/GI; re-verify columns each release

Have a rollback ready before you start

Rolling back an Acumatica upgrade is not a code revert — the database schema has moved forward. In practice the safe rollback is a restored pre-upgrade backup of both the application and the database, which is exactly why you take one immediately before starting and confirm it restores cleanly. Treat the upgrade as reversible only up to the point where users start entering new transactions on the new version; after that, forward-fix is your only path, so front-load the testing accordingly.

Wrapping up

Upgrade survival is unglamorous and almost entirely preventable: extend instead of edit, prefix your fields, keep the project unpacked in Git, and rehearse the upgrade on a copy of production before you touch the real thing. Do that and an upgrade becomes a scheduled, boring maintenance task instead of the Friday-evening emergency it turns into for teams that customized past the seams.

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.