Angular 22.1 landed on July 29th, 2026, and it’s a minor release. But it comes with an announcement that changes how all of us plan our upgrades: Angular is switching to one major release per year.
New release schedule
Since Angular 4, we’ve had a major release every six months. That’s over, and here’s what it means concretely:
- One major version every year, in June
- v23 lands in June 2027 — not November 2026
- v24 in June 2028, and so on
- Major versions are now supported for two years instead of 18 months
- Minor releases keep coming about every two months, so 4 to 6 per year
I’ve been teaching Angular upgrades for years now, and this is the change teams have been asking for.
The next release is v22.2, expected in September 2026.
Migrating @Injectable to @Service
Angular 22 introduced the new @Service() decorator, and the CLI has been generating services with it ever since. What was missing was a way to migrate the services already in your codebase. Angular v22.1 adds that schematic:
ng generate @angular/core:service
It converts this:
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class UserService {
// ...
}
Into this:
import { Service } from '@angular/core';
@Service()
export class UserService {
// ...
}
A bare @Injectable() becomes @Service().
The migration is conservative. It skips services that use constructor-based dependency injection, services passing options other than providedIn, and anything where providedIn isn't 'root'. Run it with the –dry-run option first to get an idea of how many files will get updated.
A custom setter for linkedSignal
linkedSignal is what you reach for when you want a signal derived from another signal that you can also write to — something computed can't do:
readonly items = signal<Array<ItemModel>>([]);
protected readonly selectedItem = linkedSignal(() => this.items()[0]);
In v22.1, you can pass a custom set function to control what happens when you write to it:
protected readonly selectedItem = linkedSignal(() => this.items()[0], {
set: (item: ItemModel) => {
const items = this.items();
if (items.indexOf(item) < 0) {
this.items.set([item, ...items]);
}
}
});

HTTP interceptors are now untracked
Effects automatically track the signals they read, and that tracking used to extend into your HTTP interceptors. So an effect that triggered an HTTP request was silently depending on any signal your interceptors happened to read — an auth token signal, a locale signal, anything.
As of v22.1, interceptors run untracked. Your effects will now re-run only for the reasons you truly expect.
effect(() => {
const value = this.mySignal();
untracked(() => {
// do something with value
});
});
Devtools improvements
Two small improvements in Angular DevTools:
- You can now search the signal graph by name and by type, using syntax like type:computed.
- The transfer state panel has been improved and is now shown by default.

Should you upgrade?
Of course, and it should be painless if you’re already on Angular v22: ng update @angular/core @angular/cli
My name is Alain Chautard. I am a Google Developer Expert in Angular and a consultant and trainer at Angular Training, where I help development teams learn and become proficient with Angular / React / JavaScript.
If you need any help learning web technologies, feel free to get in touch!
If you enjoyed this article, please clap for it or share it. Your help is always appreciated. You can also subscribe to my articles and YouTube video page.
What’s new in Angular 22.1? was originally published in Angular Training on Medium, where people are continuing the conversation by highlighting and responding to this story.

