Acumatica · Performance

Acumatica Performance — IIS Compression

Acumatica Performance — IIS Compression is the Acumatica performance topic that nobody asks about until they have to.

John Kihiu12 min read

Compression is the cheapest performance win in the entire Acumatica stack and the one most often left at IIS defaults. Acumatica's UI ships a lot of JSON over the wire for grid data and a fair amount of static script/CSS for the SPA-style screens — both compress extremely well, and both are frequently served uncompressed on instances I inherit from previous vendors because nobody revisited the site's IIS configuration after go-live.

Static versus dynamic compression, and why both matter here

IIS distinguishes two compression features. Static compression handles files that do not change per-request — JS, CSS, images already on disk — and is cheap because IIS can cache the compressed copy after the first request. Dynamic compression handles generated responses — the JSON payloads Acumatica's screens return for grid data, GI results, dashboard widgets — and costs CPU on every request because there is nothing to cache; it is generated fresh each time.

XML — applicationHost.config / web.config
<system.webServer>
  <urlCompression doStaticCompression="true" doDynamicCompression="true" />
  <httpCompression>
    <dynamicTypes>
      <add mimeType="application/json; charset=utf-8" enabled="true" />
      <add mimeType="application/json" enabled="true" />
    </dynamicTypes>
    <staticTypes>
      <add mimeType="application/javascript" enabled="true" />
      <add mimeType="text/css" enabled="true" />
    </staticTypes>
  </httpCompression>
</system.webServer>

The application/json MIME type is the one I most often find missing from the dynamic types list on inherited instances — without it, every grid refresh and every GI result set ships uncompressed, which on a WAN link to a remote office is very noticeable and entirely avoidable.

Dynamic compression is not free — cap it

Dynamic compression trades network time for app-server CPU. On an app server that is already CPU-constrained (see the CPU profiling post in this series), turning on aggressive dynamic compression for every response can make total request time worse, not better, even though bytes-on-the-wire drop. IIS's dynamicCompressionDisableCpuUsage and dynamicCompressionEnableCpuUsage thresholds in applicationHost.config let IIS back off compression automatically when the box is already busy:

XML — CPU-aware throttling
<serverRuntime
    frequentHitThreshold="2"
    frequentHitTimePeriod="00:00:10" />
<httpCompression
    dynamicCompressionDisableCpuUsage="90"
    dynamicCompressionEnableCpuUsage="60" />

That configuration tells IIS: stop dynamically compressing once CPU crosses 90%, resume once it drops back under 60%. It is a sane default and I rarely tune it further unless profiling shows compression itself as a measurable chunk of CPU time on a specific, very high-throughput integration endpoint.

What compression will not fix

Compression reduces bytes on the wire; it does nothing for round-trip count or server-side processing time. A screen making forty separate small requests to render a dashboard is still forty round trips after you compress every one of them — that is a network-latency or client-side-batching problem, not a compression problem. Do not expect this change to fix a screen that is slow because of chattiness rather than payload size; check the browser's network tab for request count, not just size, before deciding compression is the lever to pull.

Verify it is actually on

Check the response headers in the browser's dev tools for Content-Encoding: gzip (or br if Brotli is enabled) on a grid data request, not just a static asset. It is common to find static compression enabled and working while dynamic compression is silently off because the JSON MIME type was never added — the config above looks complete but does nothing without that MIME type entry.

Wrapping up

Enable both static and dynamic compression, make sure application/json is explicitly in the dynamic types list since that is what most of Acumatica's own traffic actually is, and set CPU-aware thresholds so compression backs off under load instead of compounding a CPU bottleneck. Then check the network tab to confirm it is actually firing — a config that looks right and a MIME type list that is missing one entry look identical until you check.

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.