Today, we are thrilled to announce the release of Angular v22. We continue to be proud of the work we do with each release. Our goal is to maintain a high quality stream of features and improvements that make the workflows for developers smooth no matter how they build Angular applications.
Angular is the solid foundation upon which you can build what’s next on the web. This release features updates across stability, ergonomics and more. We want Angular to be a sort of launch pad that you can use as you build your next great application.
There’s some great features to discuss, so let’s dive in.
On the Angular team, we take a lot of joy and pride in our ability to update our APIs to bring great new features to Angular. When bringing new features to the table, we typically release a feature as experimental or developer preview. This gives the team time to gather feedback and iterate on new features. During this time, features will undergo refinement with the intention of delivering the best possible version to the community. This is great except that it means some features will not be production ready even though developers are excited and ready to use them immediately. In this release, we’re excited to be bringing 3 significant Angular features to production-ready, stable status: Signal Forms, Angular Aria and the Asynchronous Reactivity APIs.
We designed Signal Forms to be the new, robust forms API. Signal forms combine the best parts of Reactive forms, the value of strongly typed forms, as well as the things developers love about template driven forms and reactivity of signals. We put all of that together to make a reactive, composable and declarative form solution. When we launched Signal Forms in v21, we received strong signals (pun intended) from teams inside and outside of Google that we were on the right track. Since then, we’ve updated Signal Forms by:
Here’s an example of a form implementation with custom validation and template bindings:
/**
* Getting started with Signal Forms
**/
import {signal} from "@angular/core"
import {form} from "@angular/forms/signals"@Component({
selector: 'app-payment',
imports: [FormField],
templateURL: './app-payment.html',
})
class Payment {
readonly paymentModel = signal({
paymentType: '',
amount: 0
});
readonly f = form(paymentModel,
schema => {
required(schema.paymentType, {
message: 'Required field'
});
});
}
<!-- app-payment.html -->
<form>
<section>
<label for="payment-type">Payment Type:</label> <select id="payment-type" [formField]="f.paymentType">
<option value="">Select a method...</option>
<option value="credit">Credit Card</option>
<option value="paypal">Payment Service</option>
</select>
@if (f.paymentType().invalid() && f.paymentType().touched()) {
<p class="error">
@for (error of f.paymentType().errors(); track error.kind) {
<span>{{ error.message }}</span>
}
</p>
}
</section>
<button type="submit" [disabled]="f().invalid()">Submit Payment</button>
</form>
Signal Forms are ready for production today, head over to the updated guide on angular.dev to get started.
The web was meant for everyone, regardless of how someone decides to interact with it: keyboard and mouse, screen-reader or some other method. Angular teams have needed a consistent, accessible yet customizable way to build components that enables them to build apps for all users. Angular Aria was a bold step in that direction when we released it in Angular v21. We wanted developers to bring the styles and business logic while the UI directives and patterns handled the accessibility. With that in mind, Angular Aria’s set of accessibility patterns is moving to production in Angular v22. Now, developers can ship their components using Angular Aria to users with confidence.
We’ve been busy preparing it for production, here are some of the updates we’ve made:
Angular Aria’s twelve UI patterns cover common accessibility patterns and are available to use in production now. Build apps all users can enjoy.
Press enter or click to view image in full size
At the community driven 2024 NgPoland conference, Angular team member Pawel Kozlowski shared his vision for how we could take the power of signals beyond the synchronous boundaries developers were used to. What came next was the team’s exploration into what would become a game changer for Angular developers: asynchronous signals with resource. The resource API carves a path for developers to leverage the non-blocking nature of asynchronous programming while maintaining the ergonomic niceties of the standard synchronous signal API.
/**
* Code example featuring weather forecasts using resource
*/
import { resource, signal, computed } from '@angular/core';const selectedCity = signal('Chicago');
const weatherResource = resource({
params: () => ({ city: selectedCity() }),
loader: ({ params }) => fetchWeatherForecast(params.city),
});
const currentTemperature = computed(() => {
if (weatherResource.hasValue()) {
return `${weatherResource.value().temperature}°F`;
}
return 'Loading weather...';
});
While resource provided a way for developers to request asynchronous resources we wanted to provide a practical application to demonstrate what was possible. As a result, httpResource was introduced as a way to fetch data over HTTP. This new approach made fetching data much more intuitive for developers with a simplified mental model.
/**
* This snippet demonstrates how httpResource enables declarative data fetching by
* automatically tracking the selectedCity signal.
*/
export class WeatherComponent {
selectedCity = signal('Chicago'); weather = httpResource<{ temperature: number; condition: string }>(() => {
return `https://api.example.com/v1/forecast/${this.selectedCity()}`;
});
changeCity(newCity: string) {
this.selectedCity.set(newCity);
}
}
Both resource and httpResource are ready for production. As of Angular version 22, developers can now use both these APIs in their production apps with confidence knowing that they have been battle-tested and ready to serve your users.
For information on how to get with these powerful apis, visit the official guides on angular.dev.
Angular is a great choice of platform for AI-native applications. Since the introduction of angular.dev/ai, we’ve been diligently working to expand our AI story in meaningful ways to meet developers at the frontlines of this new era of development. We believe this manifests in three critical ways:
The Angular team has made significant progress in both of these areas and we’re excited to share what we’ve been working on.
As more and more developers use tools like Google’s Antigravity as their agent coding partners it is more important than ever that coding agents have the tools needed to effectively write modern Angular applications.
We’ve updated our Model Context Protocol (MCP) offering to include new tools for directly interacting with the development server while building applications.
devserver.wait_for_build allows agents to programmatically build the application and review the output for deciding next steps in the development process. For example, the build logs could reveal code errors that need to be revisited. A workflow like this enables self-healing loops for agents.
Press enter or click to view image in full size
Angular MCP also features tooling for starting and stopping the development server with devserver.start and devserver.stop, respectively. These tools create new agentic workflows to meet the needs of today’s developers.
These tools are all graduating to stable in this release along with the testing and end-to-end tools. Angular MCP features a growing list of tools to help you build modern Angular apps including the ai_tutor, modernize, onpush_zoneless_migration and more. To find out more about all the MCP tools available, check out angular.dev/ai/mcp.
Building modern Angular apps with agents
As the framework evolves, keeping up with the growing API surface can be a challenge not just for developers, but also for AI coding assistants whose training data might not capture the latest patterns. To bridge this gap, we are introducing Angular Agent Skills, a standardized way to give AI agents immediate context and expertise on modern Angular development.
These are the first two developer-focused skills:
These skills are available to use today in AI development tools like Antigravity or any environment where you run your agentic workflows.
Interested in seeing these tools in action? Check out our latest video on YouTube.
Skills to help contributors
Contributing to a major framework can be intimidating, so we’ve also rolled out a set of Contributor Skills.
These skills help explain the internal mental models required to develop features inside the Angular codebase itself. They are incredibly valuable for anyone looking to make their first pull request. We’ve found that even experienced team members discover value in reading through them to better understand the framework architecture.
Angular is excited to ship experimental support for WebMCP.
WebMCP represents an exciting new opportunity to shape the future of web interactions. It allows you to create and expose structured tools for agents to interact within the browser. Tools defined by an application allow AI assistants to interact with it directly, providing additional capabilities to the agent and reducing the need for DOM interactions.
These early iterations include support for defining tools for the entire app, routes, services. It also supports automatically generating tools from dynamic Signal Forms.
We’ve shipped docs to share more information about this new integration.
The development community is experiencing an incredible boom in “builders”. These are people who want to bring their ideas to life with software but might not come from a traditional coding background. To support them, we’ve worked closely with the teams behind Google AI Studio and Gemini Canvas to ensure these builders can kick off their projects with the foundational strengths of Angular.
Prototype Directly in the Browser
You can use the built-in coding sandbox in the Gemini web app to create a full application directly in the browser.
For example, I recently used it to build an Angular app for my kid’s soccer team to track who is responsible for bringing snacks. By specifying “Angular” in the prompt, the generated app uses Angular. Once the code is generated, you can edit it manually in the browser, or just keep chatting with the AI to refine it. You can even expand its capabilities by simply asking it to integrate Firebase for backend storage and more.
Press enter or click to view image in full size
“Vibe Coding” in Google AI Studio
You can follow a similar workflow in Google AI Studio by selecting Angular from the configuration panel and start prompting.
Press enter or click to view image in full size
Here’s the app prompt:
“I need an Angular math facts app to help my 3rd grader improve multiplication skills. Make it use flash cards and keep track of progress on specific facts they struggle with.”
Press enter or click to view image in full size
Once the application generates an application a builder can continue to iterate, add features via chat, and eventually deploy it for the world to use. The barrier to entry for turning an idea into a structured Angular app has never been lower.
If you are building great apps you are welcomed in the Angular community no matter what.
Angular’s vast API surface provides lots of value as is but we’re always working to improve it. Let’s explore some of the new features we’re bringing to developers everywhere in Angular v22.
The Angular router is a solid, foundational piece of the story that makes Angular so compelling to developers all over the world. We’re excited to bring new features to the router to help ensure your applications meet your business needs.
Join Medium for free to get updates from this writer.
Here are a few of the updates you can enjoy in the latest release.
This update aligns the router with the native browser Navigation API, giving better control over user movement across applications with less boilerplate. Here is what that looks like in practice:
RouterLink and standard anchor tags.Here’s how to enable access to this feature:
bootstrapApplication(AppComponent, {
providers: [
provideRouter(appRoutes, withExperimentalPlatformNavigation())
]
});We are introducing two new features designed to give you more precise control over memory management by explicitly cleaning up unused resources. We are actively looking for feedback on these changes to determine if they should become the framework default in future releases.
RouteReuseStrategy, disposing of cached routes historically required workarounds (like casting the opaque handle to any to manually call componentRef.destroy()). This new utility function provides an official, public API to cleanly destroy the component stored within a detached route handle.We’d love your feedback on withExperimentalAutoCleanupInjectors as we could make it the default behavior if the community finds it to be a favorable addition.
Here’s how to get started:
import {
provideRouter,
withExperimentalAutoCleanupInjectors,
} from '@angular/router';export const appConfig: ApplicationConfig = {
providers: [
provideRouter(
routes,
withExperimentalAutoCleanupInjectors(),
)
]
};
This release sees the introduction of a new decorator aimed at improving code readability and intention — @Service. Use this new decorator as a replacement of the @Injectable({ providedIn: ‘root' }) pattern for most use cases. In the event that your application use case requires deeper configuration or constructor injection, @Injectablewill still be available. We see this as a more intuitive way to define global singletons in your application.
Check out this new syntax in action:
import {Service} from '@angular/core';@Service()
export class BasicDataStore {
private data: string[] = [];
addData(item: string): void {
this.data.push(item);
}
getData(): string[] {
return [...this.data];
}
}
Sometimes applications feature large dependencies that are best loaded on demand, when needed. While Angular has supported lazy loading of components and routes, services have not been eligible for this same optimization. That all changes with the introduction of injectAsync. This new API supports asynchronous dependency injection, enabling code splitting. Support for asynchronous on-demand loading also means that applications can enjoy performance improvement.
The service must be auto-provided. Using the new @Service decorator handles this for you.
Here’s a code sample to help get started:
import {Component, injectAsync} from '@angular/core';@Component({
selector: 'app-report',
template: `<button (click)="export()">Export</button>`,
})
export class Report {
private exporter = injectAsync(() => import('./report-exporter'));
async export() {
const exporter = await this.exporter();
exporter.export();
}
}
In this example, the ReportExporter service is not loaded until it is first used. Dependencies can also be prefetched, too.
export class Report {
private exporter = injectAsync(() => import('./report-exporter'), {
prefetch: onIdle,
});
}The team is excited to see how developers can leverage this new feature to bring better performance to their applications. To learn more, head over to the official documentation for injectAsync on angular.dev.
If you are building great apps you are welcomed in the Angular community no matter what.
This release is packed with even more API-related features, including:
This release has quite a few quality of life improvements designed to make authoring Angular templates better than before.
Code documentation serves as a vital tool for both developers and coding agents, allowing them to clarify the intent behind code or flag work that is in progress or planned for the future. To expand these documentation capabilities, we have introduced support at the element level, offering new ways to document code specifically at the property and binding level.
<div
// valid comment
/* another valid comment */
attr1="value1"
/*
a valid comment
spanning multiple
lines
*/
attr2="value2">
</div>With this change you can now comment properties and bindings in templates for increased readability and clarity. As a plus, VS Code comment toggling is also supported.
Angular now automatically de-duplicates host directives that match multiple times on the same element. To ensure clear resolution, if a directive matches both through the template and as a host directive, the template match “wins.” We’ve also streamlined the experience by merging the input and output maps of host directives. Finally, to maintain a clean API, Angular will now throw an error if an input or output is exposed under multiple names, preventing potential naming conflicts.
Your templates are more expressive with support for spread and rest syntax. This update works with object literals, array liberals and function calls.
Here’s an example based on a component used in a coffee shop style application:
<section>
<div [class]="{
...standardCupStyles,
'cardboard-sleeve': isHotDrink
}">
</div> <app-bakery-cart [pastryOrder]="[...dailyPastryBasics, 'croissant', 'muffin']"/>
<p>
Total Cost: ${{ calculateBill(...baseItemPrices, salesTax, espressoShotPrice, syrupPrice) }}
</p>
</section>
Developers can enjoy less verbose templates with multiple case matching in @switch statements. In the following example, two of the cases can share the same output, reducing unnecessary code duplication.
<section>
@switch (orderStatus) {
@case ('Pending')
@case ('Processing') {
<p class="badge-blue">In progress</p>
}
@case ('Shipped') {
<p class="badge-green">On its way!</p>
}
@default {
<p class="badge-gray">Unknown</p>
}
}
</section>Another helpful update to the @switch syntax is exhaustive checks for @switch blocks. With the introduction of exhaustive checks for @switch blocks, developers using union types will now receive compile-time errors if any potential values remain unhandled. To enable this check use the never value in the default case:
<section>
@switch (orderStatus) {
@case ('Pending')
@case ('Processing') {
<p class="badge-blue">In Progress</p>
}
@case ('Shipped') {
<p class="badge-green">Shipped</p>
}
@default never;
}
</section>Many developers have wanted to inline simple functions in templates but the template syntax restricted the ability to author functions directly in Angular templates. In the latest version of Angular, inline functions are valid in templates — with a few caveats.
<p>Stock: {{ item().stock }}</p><button
(click)="item.update(p => ({ ...p, stock: p.stock - 1 }))">
Decrease Stock
</button>
As long as functions are not long running, it is fine to call a function in a template 🙂
We’ve made two important changes to the way developers specify details for change detection in components.
First, OnPush is now the default for new applications. This shift brings new applications in alignment with zoneless being the default for applications. This also, in turn, aligns well with Angular’s goal of performance by default. Now that it is the default, it also is no longer required to specify OnPushas a change detection strategy in components.
// This component is using OnPush by default
@Component({
selector: 'app-weather',
template: `<section>Loading Weather...</section>`
})Second, the previous default, ChangeDetectionStrategy.Default is now called ChangeDetectionStrategy.Eager. This renaming helps developers who come across it reason with more clarity about what it does and how it impacts applications during change detection cycles.
@Component({
selector: 'app-weather',
template: `<section>Loading Weather...</section>`
changeDetection: ChangeDetectionStrategy.Eager
})Let’s shift gears and turn our attention toward everyone’s favorite topic: template errors. Template errors can be frustrating and difficult for developers and users. Developers try to develop defensive patterns in the component code while users may end up with a broken page. If that crash happens inside a high-stakes flow such as an e-commerce checkout, a single broken component can completely derail the user experience, bounce customers, and directly impact revenue. Angular is introducing a much-needed solution to improve this part of the application experience. Meet @boundary, a new API for implementing error boundaries directly within Angular templates.
Here’s an example of the syntax:
<section>
<!-- Errors that bubble up through the promotional widget are caught -->
@boundary {
<app-promotional-widget />
}
@error (let err){
<!-- Fallback content -->
<app-default-promo-widget />
}
<app-cart-summary />
<app-checkout-flow />
</section>By wrapping critical or unpredictable code blocks in the new @boundary syntax, an isolated component failure will no longer take down the entire page. Errors are caught and developers can specify fallback content. It’s a significant win for both developer and user experience.
@boundary will be available as a developer preview in Q3 2026.
Webpack support, @angular-devkit/build-angular builders, @ngtools/webpack, etc. is deprecated in v22. We’re focusing on TSGo support in the application builder. We will be sharing more details in upcoming updates.
For more information on deprecations in this release, please review the Angular CHANGELOG.
Angular v22 is more than just a collection of features; it is a commitment to the stability you rely on and the innovation you deserve. We can’t wait to see what you build on top of this foundation. Be sure to watch the official release event premiering June 5th 2026 at 9AM Pacific.
Get out there and build great apps.