Skip to content
Engineering

Angular performance: signals, zoneless and the new defaults

RVRahul Verma·4 May 2026·2 min read

What zoneless change detection and signals actually change about how you build, and where the real performance wins hide.

What zoneless actually changes

For years Angular relied on zone.js monkey-patching browser APIs so the framework knew when something might have changed. It worked, at the cost of a large polyfill and change detection running far more often than necessary — every timer, every XHR, every DOM event, regardless of whether anything was actually different.

Zoneless removes that. Change detection runs when a signal that a template depends on actually changes. The polyfill disappears from the bundle and the framework stops doing speculative work.

The catch is that anything mutating state outside Angular’s awareness no longer triggers an update by itself. In practice, if you were already using OnPush and signals, you will barely notice. If you relied on zone.js catching mutations in callbacks, that is where the migration work lives.

“Zoneless does not make a slow app fast. It stops a fast app being made slow by accident.”

Signals reward narrow dependencies

A signal is a value that knows who reads it. When it changes, only the computations and templates that depend on it are re-evaluated.

This makes granularity matter. A single object signal holding a whole page of state will invalidate everything reading any part of it. Several focused signals — or `computed` values derived from them — keep updates local. The mental model is closer to a spreadsheet than an event bus.

Use `computed` for derived state rather than recalculating in the template. It memoises, and it makes the dependency graph explicit to anyone reading the component later.

The real wins are still not in the framework

It is easy to spend a week on change-detection micro-optimisation and ship a page that is slower than one built with no optimisation at all. On most sites the dominant costs are network and rendering, not framework overhead.

Fonts are usually the largest single lever. A variable font pulled in through a CSS import is not discoverable by the preload scanner until that CSS parses, which delays text rendering. Self-host, declare the `@font-face` yourself, preload the file and use `font-display: swap`.

After that: prerender everything you can, keep hashed assets on immutable cache headers, and give images explicit dimensions so layout does not shift. None of this is exciting. All of it beats a clever change-detection trick.

Deferred loading has an SEO edge

`@defer` is genuinely useful for keeping heavy, interactive widgets out of the initial bundle. It is also a quiet way to remove content from your prerendered HTML.

Deferred blocks are not present in the static output. For a chat widget or a dashboard that is exactly what you want. For a section containing text you would like a search engine or an answer engine to read, it is a mistake that is easy to make and hard to notice, because the page looks correct in a browser.

Our rule: defer interactivity, never content.

Measure on the field, not the lab

A local Lighthouse run on a fast laptop over fibre tells you very little about a user on a mid-range Android phone on a congested network. Treat lab scores as a debugging tool and field data as the truth.

Set a performance budget that fails the build, and watch Core Web Vitals from real users. A regression that only shows up on real devices is the one that costs you conversions.

Where ITLabz can help

If you’re tackling problems like these, our engineers have built them in production across lending, fintech, logistics, manufacturing and retail. We’d be glad to compare notes.

Let’s build something exceptional.

Book a free discovery call. We’ll map your idea to a costed, de-risked delivery plan — no obligation.