acuamitca.com logo ACUAMITCA
~/blog/article

Acumatica Customization: The Ultimate Do's and Don'ts Guide

Acumatica Best Practices 15 mins read August 07, 2026

Common mistakes developers make and how to avoid them

Acumatica's customization framework is one of its greatest strengths—but also one of its biggest risks when done incorrectly. Poorly designed customizations often lead to upgrade failures, performance issues, and long-term maintenance challenges. This guide compiles the most common mistakes developers make and provides clear guidance on how to avoid them.

⚡ The Reality: Acumatica releases major updates twice a year (March R1 and September R2). Customizations that don't follow platform conventions can become upgrade blockers, performance bottlenecks, and maintenance burdens .


Part 1: Critical Do's

✅ DO Use the "Usr" Prefix for Custom Fields

Custom columns added to Acumatica's standard tables must start with "Usr" – this is what tells the upgrade process to preserve them. Columns without the prefix may be removed during an upgrade.

// ✅ CORRECT
[PXDBString(50)]
[PXUIField(DisplayName = "UsrCustomField")]
public virtual string UsrCustomField { get; set; }

// ❌ WRONG - May be removed during upgrade
[PXDBString(50)]
[PXUIField(DisplayName = "CustomField")]
public virtual string CustomField { get; set; }

✅ DO Use the Validate Project Prefix Tool

Acumatica provides a built-in tool to validate that all new objects in your solution comply with naming conventions. Select File > Validate Project Prefix in the Customization Project Editor menu. This ensures:

  • All new objects follow proper naming conventions
  • Customizations remain upgrade-safe
  • ISV certification requirements are met

✅ DO Follow Naming Conventions

Acumatica has specific naming conventions for tables (DACs) and columns (fields) :

Suffix Usage
ID Surrogate keys (e.g., CustomerID)
CD Natural keys (e.g., CustomerCD)
Nbr Numbering identifiers (e.g., OrderNbr)
Amt Amounts (e.g., FreightAmt)
Qty Quantities (e.g., OrderQty)
Date Dates (e.g., OrderDate)

⚠️ Critical: Do not use the underscore symbol (_) in table or column names—it is a reserved symbol in the Acumatica Framework [citation:3].

✅ DO Use Development Environment First

Always conduct customization work in a separate development environment rather than directly in production. Acumatica recommends a three-environment workflow: development → staging → production .

✅ DO Use Version Control

Every customization should be developed using version control (Git or equivalent systems), with a dedicated repository and full commit history. Each commit should be tied to a specific requirement and represent a logical, reviewable change .

✅ DO Use Generic Event Handlers

Modern Acumatica development favors generic event handlers over classic ones—they're easier to declare, use, and validate in Visual Studio.

// ✅ RECOMMENDED - Generic handler
protected virtual void _(Events.RowSelected<SOOrder> e)
{
    // Business logic here
}

// ❌ LESS PREFERRED - Classic handler
protected virtual void SOOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
    // Business logic here
}

✅ DO Package All Database Changes in Customization Projects

All solution-specific database schema changes must be packaged into a customization project. SQL scripts are strictly prohibited unless they are provided as part of database upgrade scripts .

💡 Pro Tip: Use the Customization Project Editor to package all changes—this ensures they can be cleanly removed if needed and remain upgrade-safe .


Part 2: Critical Don'ts

❌ DON'T Use PXDefault Without Proper PersistingCheck

The PXDefault attribute used without PersistingCheck = PXPersistingCheck.Nothing on custom fields defined in PXCacheExtension can prevent persisting of records to the database [citation:2].

// ❌ WRONG - Causes PX1030 warning/error
[PXDefault(0)]
public virtual int? UsrLineCounter { get; set; }

// ✅ CORRECT - With PersistingCheck
[PXDefault(0, PersistingCheck = PXPersistingCheck.Nothing)]
public virtual int? UsrLineCounter { get; set; }

// ✅ CORRECT - Alternative using PXUnboundDefault
[PXUnboundDefault]
public virtual bool? Selected { get; set; }

⚠️ Note: If a DAC extension includes a bound field with PXDefault without PersistingCheck = PXPersistingCheck.Nothing, a warning is displayed. For unbound fields, an error is displayed [citation:2].

❌ DON'T Use .Result or .Wait() in Acumatica Code

Just like in standard ASP.NET Core, blocking on asynchronous code in Acumatica can cause deadlocks and thread-pool starvation. Always use await and propagate async all the way.

// ❌ WRONG - Can cause deadlocks
var result = service.GetDataAsync().Result;

// ❌ WRONG - Also dangerous
service.SaveDataAsync().Wait();

// ✅ CORRECT - Async all the way
var result = await service.GetDataAsync();

❌ DON'T Use ServiceLocator Pattern for Dependencies

In Acumatica 2026 R1, the framework has been refactored to support constructor-based dependency injection. The ServiceLocator pattern limits testability and makes plug-ins harder to maintain [citation:1].

// ❌ OLD - ServiceLocator pattern (limited testability)
protected async Task<HttpResponseMessage> ExecuteAsync(HttpRequestMessage request)
{
    using (var client = ServiceLocator.Current.GetInstance<IHttpClient>())
    {
        var response = await client.SendAsync(request);
        return response;
    }
}

// ✅ NEW - Constructor-based DI (2026 R1+)
public class MyPaymentPlugin : ICCProcessingPlugin
{
    private readonly IHttpClient _httpClient;

    public MyPaymentPlugin(IHttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    protected async Task<HttpResponseMessage> ExecuteAsync(HttpRequestMessage request)
    {
        var response = await _httpClient.SendAsync(request);
        return response;
    }
}

❌ DON'T Modify Core Acumatica Code Directly

Never modify base Acumatica code directly—always use the extension model . Direct modifications will be lost during upgrades and can cause significant maintenance issues.

  • Use PXGraphExtension for graph customizations
  • Use PXCacheExtension for DAC extensions
  • Use PXOverride for method overrides
  • Use PXAction for custom actions

❌ DON'T Skip Documentation

Document everything throughout the customization process. Not only will this help with current projects, but it will also be invaluable for future modifications or troubleshooting .

  • Maintain a Functional Specification Document (FSD) with screen-by-screen behavior, field logic, and edge cases
  • Document all customizations in the Customization Project Editor
  • Keep a changelog for all modifications

❌ DON'T Start Coding Without Requirements

Before estimating or designing anything, focus on discovery and validation :

  • Which Acumatica version is in use?
  • Are there out-of-the-box features that already solve part of the request?
  • Is a hybrid approach (OOTB + targeted customization) possible?

💡 Pro Tip: Use visual aids like screen sketches, workflow diagrams, and UI behavior examples to align expectations before development begins .


Part 3: Best Practices Summary

✅ Start Simple

Use no-code and low-code options (Business Events, Screen Customizations, Generic Inquiries) before writing code .

✅ Use AI-Assisted Development

Leverage AI tools to generate C# code—describe the functionality you want and it can generate the necessary code .

✅ Publish Before Adding Controls

When adding a database-backed custom field, publish first so the system creates the column, then add the corresponding control .

✅ Group Related Changes

Group related changes in the same customization project for easier management and conflict resolution .

✅ Follow Coding Standards

Use standard .NET coding conventions and Acumatica development guidelines. Keep classes and methods small and readable .

✅ Test Thoroughly

Rigorously test custom features to confirm they work as intended—preferably in staging environment first .


Common Pitfalls Summary

❌ Customizing Without Upgrade Planning

Always consider how customizations will survive major releases. Use the "Usr" prefix for custom fields and follow Acumatica guidelines .

❌ Overlooking Performance

Avoid heavy operations in frequently fired events like RowSelected and FieldDefaulting.

❌ Creating SQL Scripts

SQL scripts for database changes are strictly prohibited—use Customization Projects instead .

❌ Skipping Staging Environment

Test in staging (a copy of production) before going live, including interactions with other customizations .

❌ No Version Control

Every customization must be in version control with proper commit history and traceability .

❌ Not Using Debug Settings

Configure web.config with debug settings to surface errors and automation steps during development .


Development Environment Configuration

To optimize your development experience, add these settings to your web.config file :

<configuration>
    <appSettings>
        <!-- Enable website debugging -->
        <add key="AutomationDebug" value="True" />
        
        <!-- Optimize startup time -->
        <add key="InstantiateAllCaches" value="False" />
        <add key="CompilePages" value="False" />
        
        <!-- Disable scheduler during development -->
        <add key="DisableScheduleProcessor" value="True" />
    </appSettings>
    
    <system.web>
        <compilation debug="true" />
    </system.web>
</configuration>

These settings enable page validation warnings, show automation steps, and optimize instance startup—saving significant development time .


The Bottom Line

📌 Key Takeaway: Successful Acumatica customization requires discipline, planning, and adherence to platform conventions. Use the extension model, follow naming conventions, test thoroughly, and always think about upgrade safety. The extra effort upfront saves countless hours of maintenance and upgrade headaches later.

🔍 Further Reading: Explore Acumatica's official documentation for detailed guidance on specific topics. The Acumatica Developer Network (ADN) provides comprehensive resources for developers at all levels .