What Zone.js Actually Did — and Why It Had to Go In short: Most Angular developers used Zone.js for years without reading a word about it. It is worth understanding now, precisely because it is being removed — the things that break during that move are exactly the things Zone.js was quietly doing for you. How it worked When your app started, Zone.js replaced the browser's own functions with its own versions: It did this for , , , , , , and a long list of others. Any time one of them finished, Angular was told. On being told, Angular ran a check: walk the whole component tree from the top, work out every template value again, compare each to what it was before, and update the page where they differ. That is the whole system. Notice what is missing — at no point does Angular know what changed. It only knows that something finished, so anything might have. What this bought Genuine, large convenience. You could write this and it simply worked: No special update call, no signal, no subscription. Change a value and the screen updates. Angular got this right early and it was a big part of why the framework felt productive. What it cost Everything gets checked. One keypress in a search box triggers a walk of the whole tree. With a few hundred components and a few thousand values, that is real work on every single event. existed to cut the walk short — which is why performance-minded projects used it everywhere. It was a manual fix for a problem the design created. It costs download size and startup time. Angular's zoneless guide puts it plainly: Zone.js "brings a fair amount of overhead, both in payload size and startup time." It is a polyfill that must run before your app, on every page load. Error reports became hard to read. Because every delayed call went through Zone.js, error traces were full of Zone.js lines between your code and whatever called it. Angular's own guide lists clearer stack traces as one of the reasons to go zoneless. It could not handle / . The docs state this directly: "Zone.js can't monkey patch async/await, so the Angular CLI needs to downlevel it to promises." Your modern code was being converted to older code so Zone.js could see it. And a library that captured a reference to a browser function before Zone.js loaded would not trigger an update either — the classic "I have to call here and I do not know why." Tests needed a whole vocabulary. , , , and all exist because tests needed to control and wait for the zone. That is an entire set of testing tools existing only to manage this one mechanism. The pressure valve. When a very frequent callback should not trigger an update, you escaped: Any project doing drawing, dragging, scroll handling, or charts has this pattern somewhere. It is also the clearest evidence the model was backwards. The default was to assume everything mattered, and you had to opt specific things out . Why signals removed the need A signal knows which templates read it. When it changes, it marks exactly those components and schedules a targeted update: No replaced browser functions. No tree walk. No polyfill. And the information is better than Zone.js ever had: "this value changed, and these three components read it" instead of "a timer fired somewhere, better check all 400 components." Once that existed, Zone.js was doing a worse job at a higher cost. What tells Angular in a zoneless app Zoneless does not mean doing it by hand. Angular is still told — it just gets told directly instead of guessing: A signal read in a template changes A template event fires — , , and so on An pipe produces a value A query result changes is called A host binding value changes An changes status or value That covers essentially all normal app code. What is not covered is the gap: a that assigns to a plain property, a library callback that changes a property, a promise that sets a non-signal value. Those used to work by accident. They stop working, and the fix is to make the value a signal — which is what it should have been. What you get back Angular's zoneless guide lists four benefits: Benefit What it means --- --- Performance Angular checks only what was reported as changed, instead of treating every async task as a signal that something might have Core Web Vitals Zone.js overhead in both payload size and startup time goes away Debugging Stack traces no longer route through Zone.js Ecosystem compatibility Removes a source of complexity, monkey patching, and ongoing maintenance The guide also notes that the zoneless scheduler coalesces work — so a single button click runs change detection once, rather than once per async task the click happened to start. The architect's view The thing to take from this lesson is a general principle , not Zone.js trivia: a system that has to guess compensates by doing more work. Zone.js could tell that something finished. It could never tell what changed . Having only that, the safe response is to check everything. It was a reasonable design given what wa…