Acumatica · Architecture

Acumatica Architecture — A Primer for New Developers

A clear, beginner-friendly walk through the Acumatica architecture — the platform, the customization layer, the database, the web tier, and the mental model you need before you write your first line of code.

John Kihiu12 min read

Every developer I onboard onto an Acumatica project asks some version of the same question in week one: "where do I even start reading?" Acumatica is not a small framework, and unlike a typical web stack you cannot get productive by learning one library — you need a mental map of five or six layers that all talk to each other. This is the map I actually draw on a whiteboard for new hires.

Three physical tiers, one logical model

Physically, an on-premise or private-cloud Acumatica deployment is a fairly ordinary ASP.NET application: IIS hosts the web tier, which talks to SQL Server (or on some deployments, other RDBMS options historically supported), with an optional separate application server tier for scale-out. SaaS instances hide all of this behind a URL, but the logical model underneath is identical whether you can see the servers or not.

Logically, though, Acumatica is not "MVC with a database." It is built around a small number of recurring abstractions that show up everywhere once you learn to spot them:

Everything else — Generic Inquiries, the REST API, Business Events, the mobile framework, Modern UI — is built on top of these five ideas, not alongside them. Learn these cold and the rest of the platform stops looking like a pile of unrelated screens.

What actually happens when a screen loads

Trace a single page load and the abstractions click into place. The browser requests the screen; the web tier resolves the screen ID to a graph type and instantiates it (or resumes it from session state — graphs are stateful across a user's editing session, which surprises developers coming from stateless web frameworks). The graph's primary PXSelect view executes a BQL query, populating a cache. Each row entering the cache fires RowSelected for every field, letting attributes and your event handlers adjust UI state — enabling fields, applying conditional visibility — before the grid ever paints. The rendered screen definition (ASPX markup, or a Modern UI screen definition file) maps controls to DAC fields by name, and that is the entire binding mechanism; there is no separate view-model layer to configure.

Saving reverses the flow: edits mutate cache-tracked rows, RowPersisting fires per row as a last validation gate, and only after every row passes does the graph open a transaction and call each DAC's persist logic. One unhandled exception anywhere in that chain rolls the whole save back — Acumatica does not do partial saves, which is a deliberate consistency guarantee worth knowing before you're tempted to catch-and-swallow an exception "just for this one field."

Sessions are stateful, and that has consequences

Because a graph instance persists across requests for the duration of a user's screen session, code that "leaks" — a static field holding request-specific data, an event handler that assumes it only runs once — causes bugs that only appear after a user navigates away and back, or after the app pool recycles under load. Coming from stateless REST controllers, this is the single biggest mental adjustment.

The one rule that explains the rest of the framework

Acumatica's customization model exists to answer one question: how do you let thousands of partners modify the same shipped codebase without forking it? The answer is extension, never modification. PXCacheExtension<T> adds fields to a DAC without touching its source. PXGraphExtension<T> adds behavior to a graph the same way. Screen customizations layer UI changes on top of a base screen definition rather than replacing the file. Every layer of the platform — DAC, graph, screen, even reports — follows this same extend-don't-replace pattern, and once you see it in one place you recognize it everywhere, including in the newer Modern UI and Mobile frameworks that arrived years after the core model was designed.

A realistic first-month reading order

I tell new developers to resist the urge to read the whole T200/T300 training catalogue up front. Instead: build one small customization end-to-end (a custom field, a validation rule, a button) to see the DAC/graph/screen triangle in miniature; read the DAC fundamentals material until attributes stop feeling like magic; then spend real time in the event pipeline until RowSelected-vs-RowInserted-vs-RowPersisting firing order is intuitive, because that firing order is where most beginner bugs live. Everything past that point — Generic Inquiries, the REST API, Business Events, Modern UI, Mobile — is a specialization of the same five ideas, easier to pick up once, not five times.

Wrapping up

Acumatica rewards developers who learn the shape of the framework before they learn any specific screen. DAC, graph, cache, BQL, and the event pipeline are the whole game; extension-over-modification is the rule that makes the whole game upgrade-safe. Everything else you'll touch on a real project is built from those pieces, so time spent understanding them properly in week one saves months of confused debugging later.

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.