
Angular 19: A Detailed Guide to New Features and Paradigms
Angular 19 is a major release focused on developer experience, performance, and modernizing the framework’s foundations. Released in late 2024, it introduces significant improvements in server-side rendering (SSR), a revamped reactivity model, streamlined component architecture, enhanced developer tooling, strengthened security, and new Angular Material UI components. In this guide, we break down Angular 19’s features into categories relevant to frontend developers—covering what’s new, how it works (with examples), pros and cons, and tips for migrating from previous versions.
Key Highlights of Angular 19 (What’s New in Angular 19: Key Features and Updates | by Rajat Gupta | Medium):
Standalone Components by Default – Angular now uses standalone components, directives, and pipes as the default, simplifying project setup and module management (What’s New in Angular 19: Key Features and Updates | by Rajat Gupta | Medium).
Route Rendering Control (SSR) – Fine-grained control over whether routes render on the server, prerender (static), or client-only, boosting performance and SEO (What’s New in Angular 19: Key Features and Updates | by Rajat Gupta | Medium).
Reactivity Boost – New signal-based reactivity primitives (
linkedSignal
andresource()
) for state management and asynchronous data handling (What’s New in Angular 19: Key Features and Updates | by Rajat Gupta | Medium).Security with AutoCSP – Automatic generation of strict Content Security Policy hashes for inline scripts, improving security out-of-the-box (What’s New in Angular 19: Key Features and Updates | by Rajat Gupta | Medium).
Angular Material Enhancements – A long-awaited Time Picker component and two-dimensional drag-and-drop support in the CDK, plus theming API improvements (What’s New in Angular 19: Key Features and Updates | by Rajat Gupta | Medium).
Automatic Code Migrations – Schematics and IDE tooling to update your code to best practices (e.g. converting to standalone components, lazy loading routes, etc.) (What’s New in Angular 19: Key Features and Updates | by Rajat Gupta | Medium).
Each section below dives deeper into these areas. By the end, you’ll understand not only what Angular 19 introduces, but why it matters, with practical examples and guidance for adopting these features in your projects.
Server-Side Rendering and Hydration Enhancements
Angular 19 brings major advances to server-side rendering, aimed at faster loads and better interactivity for users. Key SSR features include incremental hydration, route-level rendering modes, and event replay – all geared towards delivering content efficiently without overwhelming the client.
Incremental Hydration (Developer Preview)
What it is: Incremental hydration is a new way to hydrate (make interactive) a server-rendered app in parts, instead of all at once. In earlier Angular versions, when using full hydration, the entire page’s JavaScript had to load before it became interactive. Angular 19 introduces partial, on-demand hydration of components marked as deferrable (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Angular 19 features: A Know It All Guide). You can designate parts of the template to hydrate lazily via the familiar @defer
directive.
How it works: With incremental hydration, you annotate sections of your template that should load lazily upon certain triggers (like entering the viewport or user interaction) rather than immediately on page load (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Angular 19 features: A Know It All Guide). For example, to defer hydrating a large component until it scrolls into view:
@defer (hydrate on viewport) {
<large-cmp></large-cmp>
} @placeholder {
<div>Loading content…</div>
}
In this snippet, <large-cmp>
(and its associated JS) won’t load until the component is about to enter the viewport (Angular 19 features: A Know It All Guide). Angular uses the Intersection Observer API under the hood to trigger hydration when needed (Angular 19 features: A Know It All Guide). Incremental hydration is enabled by adding the withIncrementalHydration()
option when bootstrapping the client app:
import { provideClientHydration, withIncrementalHydration } from '@angular/platform-browser';
bootstrapApplication(App, {
providers: [provideClientHydration(withIncrementalHydration())]
});
This opt-in configuration tells Angular to perform hydration in chunks. Parts of the UI remain in a “gray” or inactive state until their turn to hydrate, as illustrated by Angular’s demo (grayed-out components become colored once hydrated) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Pros:
Faster page interactivity: Critical UI loads first, reducing time to first interaction. Non-critical sections don’t block the initial render (Angular 19 features: A Know It All Guide) (Angular 19 features: A Know It All Guide).
Reduced JS payload: Only the code needed immediately is downloaded upfront; remaining chunks load on demand, which improves load times on slow networks (Angular 19 features: A Know It All Guide) (Angular 19 features: A Know It All Guide).
Better UX on long pages: Users can start interacting with visible content while offscreen content hydrates later (e.g. reading an article – the top loads first, lower sections hydrate as user scrolls) (Angular 19 features: A Know It All Guide).
Cons:
Still in preview: Incremental hydration is a developer preview in v19, so the API or behavior may evolve (Angular 19 features: A Know It All Guide). Caution is advised if using in production.
Complexity: Developers must thoughtfully annotate templates with
@defer
triggers. Improper use could result in parts of the UI remaining inactive longer than intended. Debugging partially hydrated apps may be more complex than traditional full hydration.Browser support: Relies on modern browser APIs (like Intersection Observer). Most modern browsers support these, but it’s something to consider for very old environments.
Overall, incremental hydration is poised to deliver faster, more resilient SSR. As one blog puts it, “full-scale hydration can cause serious issues… incremental hydration [lets] only the part being read be interactive, while the rest wait until the reader reaches that part” (Angular 19 features: A Know It All Guide) (Angular 19 features: A Know It All Guide). This feature should significantly improve performance for content-heavy apps, once it matures.
Route-Level Render Modes
What it is: Angular 19 gives you fine-grained control over how each route is rendered – on the server, prerendered at build time, or client-side only (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). By default, when SSR is enabled, Angular would server-render all routes with parameters and prerender static routes without parameters (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). Now, using a ServerRoute
configuration, you can override this per route.
How it works: You define an array of route render rules (e.g. in a server.routes.ts
file) and provide it to the SSR configuration. Each rule maps a route path (with optional wildcards) to a RenderMode
strategy:
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRouteConfig: ServerRoute[] = [
{ path: '/login', mode: RenderMode.Server }, // SSR on every request
{ path: '/dashboard', mode: RenderMode.Client }, // client-only render (no SSR)
{ path: '/**', mode: RenderMode.Prerender } // prerender all other routes at build time
];
In the above example, the /login
page will always be server-rendered, /dashboard
will only render on the client, and all other routes (/**
) will be prerendered as static HTML during build (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). This configuration composes with your existing route definitions (using path globs) so you don’t duplicate route info (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Crucially, this system also enables resolving dynamic route parameters at build-time for prerendering. For instance, suppose you want to prerender pages for each product ID:
export const routes: ServerRoute[] = [
{
path: '/product/:id',
mode: RenderMode.Prerender,
async getPrerenderParams() {
const dataService = inject(ProductService);
const ids = await dataService.getIds(); // e.g. ['1','2','3']
return ids.map(id => ({ id })); // produce routes /product/1, /product/2, /product/3
}
}
];
Here, getPrerenderParams()
runs at build time to fetch all product IDs (using dependency injection to reuse your ProductService
logic) and tells Angular to prerender /product/1
, /product/2
, etc. (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). This was previously not ergonomic to do; Angular 19 makes it seamless to prerender multiple pages based on data (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Pros:
Selective performance optimization: You can SSR only what truly benefits from it (like marketing or SEO-critical pages) and skip SSR for heavy admin pages or user-specific dashboards where it’s less useful (What’s New in Angular 19: Key Features and Updates | by Rajat Gupta | Medium) (What’s New in Angular 19: Key Features and Updates | by Rajat Gupta | Medium). This can reduce server load and Time-to-Interactive for certain routes.
Better SEO: Prerendering or SSR routes that need search indexing ensures crawlers get fully rendered HTML (What’s New in Angular 19: Key Features and Updates | by Rajat Gupta | Medium), while less important routes don’t slow down build or server time.
Flexible deployment: RenderMode choices enable a hybrid rendering strategy – e.g. use static prerender for most content, SSR for a few dynamic pages, and pure client render for others – all in one app. This was cumbersome to achieve before.
Data-driven prerendering: The ability to resolve route params at build (via
getPrerenderParams
) unlocks use cases like generating an entire set of pages from CMS or database data automatically (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Cons:
Developer preview: As of v19, route-level render mode is in developer preview, so its API might change (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). Use in production should be carefully evaluated.
Additional configuration: This feature introduces another config file to maintain. Misconfiguring could lead to some routes not being SSR’d when intended (or vice versa). It’s an extra layer of complexity for SSR setups.
Build time considerations: If using extensive prerendering (e.g. thousands of dynamic pages via
getPrerenderParams
), build times could increase. Developers must balance build-time prerendering vs. on-demand SSR based on app needs.
Overall, route-level rendering control is a powerful feature for advanced performance tuning. As one overview noted, this feature “unlocks advantages such as improved SEO and flexibility” when wisely applied (Angular 19 features: A Know It All Guide). Expect the API to stabilize in future releases, making it a standard tool for Angular SSR projects.
Event Replay (Stabilized)
What it is: Event replay addresses a classic problem in SSR: what if a user interacts with a server-rendered page before the client-side JavaScript is fully loaded? Angular 19 enables an event capture/replay mechanism by default to ensure no user event is lost during that “hydration gap” (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
How it works: When a server-rendered page first loads in the browser, Angular’s event replay (built on the @angular/platform-browser
event dispatch library) will capture events (clicks, inputs, etc.) that occur before the relevant event handlers have been registered. Once the lazy JavaScript for that part of the UI is loaded and the component is hydrated, Angular replays those queued events so that the intended onClick/onChange logic still runs (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). In Angular 18 this was an opt-in experimental feature; in Angular 19 it’s graduated to stable and new SSR projects have it enabled by default (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Enabling event replay manually is as simple as adding withEventReplay()
to your hydration provider (though Angular CLI sets this up for you on new apps):
bootstrapApplication(App, {
providers: [provideClientHydration(withEventReplay())]
});
Now, if a user rapidly clicks a button on an SSR page, the click will be buffered until Angular loads that button’s component code, and then it will execute as if it happened afterward. A visualization from the Angular team showed how a click made during initial load is seamlessly handled once the component hydrates (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Pros:
No lost interactions: Improves UX by handling fast user interactions on SSR pages – users don’t have to click twice or experience nothing happening due to the app still loading. This makes SSR apps feel more responsive.
Battle-tested solution: This event replay system is the same one used internally by Google Search and has been “battle tested by billions of users over ten years” (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog), giving confidence in its reliability.
Zero config for new apps: It’s on by default for Angular 19 SSR, meaning developers get the benefit without extra work in most cases (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Cons:
Slight overhead: Capturing and replaying events introduces a small runtime overhead (negligible for most apps). In rare cases, if an event triggers very complex behavior, replaying it might produce different results if the state changed in between – though typically the state is frozen until hydration.
Limited to initial load: Event replay is mainly about the initial hydration phase. It doesn’t help if your app deliberately delays loading a feature long after initial load and the user interacts in the meantime (that scenario would require custom handling).
Debugging: There is a bit of “magic” – events happen, then re-fire later. This could complicate debugging of event-related issues right at startup, since the timing is non-linear.
Enabling event replay by default in Angular 19 signals Angular’s emphasis on smooth SSR experiences. It closes the gap between static content and full interactivity, making SSR more seamless for end-users.
Server-Side Rendering with Zoneless Angular (Experimental)
Angular 19 continues Angular’s journey towards Zone.js-free change detection, including on the server. Zoneless Angular means the framework can run without relying on the Zone.js
library to track async operations. Angular 18 introduced an experimental opt-in for zone-free change detection, and v19 refines it and even integrates it with SSR (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Why ditch Zone.js? Traditionally, Zone.js hooks into async APIs (timers, events, XHR, etc.) to know when to trigger Angular’s change detection. While convenient, this adds overhead and complexity. Going zoneless can improve performance (no zone patching) and reduce bundle size (Angular 19 - 5 Game-Changing Features You Need to Know - DEV Community) (Angular 19 - 5 Game-Changing Features You Need to Know - DEV Community), but it requires alternative ways to signal when to check for updates.
In Angular 19, you can experiment with zoneless mode by using a special provider at bootstrap:
bootstrapApplication(App, {
providers: [provideExperimentalZonelessChangeDetection()]
});
and by removing zone.js
from your polyfills. You can even create a new project with zoneless mode via CLI:
ng new my-app --experimental-zoneless
This sets up Angular to rely on signals and explicit triggers for change detection instead of zones. On the SSR side, Angular added primitives to delay sending the HTML until the app is ready (replacing Zone.js’s role on the server) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). For example, Angular 19 includes an RxJS operator pendingUntilEvent(injector)
that you can apply to observables to indicate the server should wait (keep rendering “pending”) until a certain async event occurs (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). This helps Angular SSR know when all needed data is loaded before finishing server rendering.
Pros:
Performance: Removing Zone.js can yield faster renders and smaller bundles, since there’s no zone overhead. Internal tests showed improved initial render speed and download size (Angular 19 - 5 Game-Changing Features You Need to Know - DEV Community) (Angular 19 - 5 Game-Changing Features You Need to Know - DEV Community).
Predictability: Change detection becomes more explicit. Developers trigger updates via signals or manual checks, which can simplify mental models and debugging (no mysterious zone context) (Angular 19 - 5 Game-Changing Features You Need to Know - DEV Community).
Modern paradigm: Aligns Angular with the direction of other frameworks (React, Solid, etc.) that don’t use zones, potentially making Angular more approachable to new developers and easier to interoperate with external code.
Cons:
Not yet stable: Zoneless mode in v19 remains highly experimental (not even developer preview). The core team is still polishing it for general use (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). It’s not recommended for production apps yet.
Migrating complexity: Large existing apps that rely on Zone.js (directly or indirectly) might need significant changes. Some libraries or patterns assume zone-based change detection; those would break or require manual triggers to update the UI.
Hybrid state: Until zoneless becomes official, developers must choose between the traditional zone approach or the experimental path. Using signals (see Reactivity section) is encouraged regardless, since signals work with or without zones and will ease future transitions.
The Angular team is optimistic about zoneless mode—one case study with Google’s Fonts website saw an easy transition and promising results (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). “The results and ease of transition exceeded our expectations,” the team noted (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). If you’re adventurous, Angular 19 lets you give zoneless a try and provide feedback before it becomes mainstream in upcoming releases (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Reactivity and State Management Improvements
One of Angular 19’s biggest themes is an evolving reactivity system. This release cements many of the signal-based APIs introduced in Angular 16-18 as stable, and adds new primitives to handle more complex state scenarios and asynchronous data. These changes make Angular’s reactive programming model more intuitive and reduce the need for manual RxJS juggling in many cases.
Signal-Based Inputs, Outputs, and Queries (Now Stable)
In Angular 16, the framework introduced signal-based versions of component inputs and other bindings as an experimental feature. Angular 19 graduates these to stable APIs, meaning you can use them in production with confidence (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). There are new functions in @angular/core
for declaring inputs, outputs, and view queries that return reactive signals.
What’s new: Instead of using the @Input()
decorator to create an input property, you can now declare an input as a signal with the input()
function. Similarly, output()
, viewChild()
, viewChildren()
, etc., create reactive counterparts for outputs and queries (What’s new with Signals in Angular 19? | Angular Newsletter) (What’s new with Signals in Angular 19? | Angular Newsletter). For example:
import { Component, input } from '@angular/core';
@Component({
selector: 'app-example',
template: '' <!-- notice we call message() as it's a signal -->
})
export class ExampleComponent {
// Before (traditional Input)
// @Input() message: string = 'Hello';
// After (signal-based Input)
message = input<string>('Hello');
}
In this migration example, the message
input becomes a signal initialized with 'Hello'
(Angular 19: What's new - by Amos Isaila) (Angular 19: What's new - by Amos Isaila). The parent component can bind [message]="someValue"
exactly as before – Angular will feed the value into the child’s signal. Inside the child, message
is now a signal: you retrieve its value by calling message()
. (Angular’s template binding automatically unwraps signals, so in the template you can still write `as shown, without the
()`, for convenience.)
Similarly, output()
can be used to create an event emitter as a signal/observable hybrid, and viewChild()
/viewChildren()
return signals that update when the referenced child view(s) change. All of the following are stable in v19: input()
, output()
, model()
(for two-way bindings), viewChild()
/viewChildren()
, contentChild()
/contentChildren()
, as well as utilities like takeUntilDestroyed()
for cleaning up subscriptions when a component is destroyed (What’s new with Signals in Angular 19? | Angular Newsletter) (What’s new with Signals in Angular 19? | Angular Newsletter). This represents a comprehensive move toward signal-based patterns.
Benefits: These APIs aim to simplify and improve component state handling: “Reactivity is the mechanism that allows apps to respond instantly to data changes… [signals] reduce the need for manual state management and rendering logic.” (Angular 19 features: A Know It All Guide) By using signals for inputs and view queries, components automatically update when those inputs or child components change, without requiring explicit OnChanges
or manual subscription to events.
Pros:
Cleaner code: No need for extra
@Input()
boilerplate orEventEmitter
imports. Signal inputs are just class properties, which can make component code more concise.Reactive updates: An input defined via
input()
is essentially a computed signal fed by the parent. That means if a parent changes the bound value, the child’s signal updates reactively. In many cases, this eliminates the need for lifecycle hooks likengOnChanges
.Synchronizes with signals ecosystem: These inputs/outputs tie neatly into Angular’s signals system. For instance, you could pass a signal from a parent to a child directly as an input; the child can treat it like a normal input property (Angular will unwrap one level of signal automatically).
Schematics support: Angular 19 provides automated migrations to convert existing
@Input
and@ViewChild
usages to the new forms (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). The CLI commandng generate @angular/core:signals
will run all related migrations (or use the specificsignal-input-migration
,signal-queries-migration
, etc.) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). Initial community feedback on these auto-migrations has been very positive, as they can update hundreds of instances quickly (What’s new with Signals in Angular 19? | Angular Newsletter).
Cons:
Read-only inputs: One difference is that signal inputs are read-only – you shouldn’t assign to
this.message
inside the child component (since its value is driven by the parent) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). If your code previously mutated an@Input()
internally, that needs refactoring (e.g. use an internal signal for mutable state, or request changes via outputs). This could require some manual adjustment during migration.Learning curve: Developers need to get comfortable with calling signals as functions to get their values. It’s a new mental model if you come from the traditional property binding world. Fortunately, Angular’s template syntax hides some of this complexity by auto-unwrapping signals in interpolation.
IDE/Tooling support: While the Angular Language Service now can suggest and even apply these migrations, some IDEs or linters might need updates to fully recognize the new patterns. Until then, you might see unfamiliar warnings (e.g., some linters might think
message = input<string>()
is a function call without using its result – which in this case is intentional).
Overall, the stabilization of signal-based inputs/outputs is a big step in Angular’s shift to a signals-first reactivity paradigm. It simplifies the component API surface and sets the stage for future zone-less change detection (signals can notify Angular of changes without zones). For developers, it means fewer manual subscriptions and lifecycle hooks, and more declarative, automatic reactivity.
New Reactive Primitives: linkedSignal
Angular 19 introduces a new experimental primitive called linkedSignal
to handle a common UI state scenario: a piece of state that is mostly derived from another state, but can also be temporarily overridden by the user. In other words, a writable computed signal that “links” to some source signals.
Use case: Imagine a list with a “currently selected item”. By default, you might want the first item to be selected. However, the user can change the selection. If the list of items changes entirely, you’d want the selection to reset to the new first item. This is tricky to implement with a normal computed signal (which is read-only) and would require manual effects.
What it is: linkedSignal(fn)
creates a writable signal that is computed from other signal(s) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). It tracks a dependency but also allows local mutations. If the dependency changes, the linked signal “resets” to the new computed value (unless you configure it to try to preserve the prior user-set value).
Example:
const options = signal(['apple', 'banana', 'fig']);
// Create a linked signal: defaults to options()[0] but can be updated
const choice = linkedSignal(() => options()[0]);
console.log(choice()); // "apple"
choice.set('fig');
console.log(choice()); // "fig" (user changed selection)
// Now update the source signal
options.set(['peach', 'kiwi']);
console.log(choice()); // "peach" (choice reset because options changed)
In this snippet, choice
is linked to options
. Initially it takes the first option (“apple”). The user (or program) can call choice.set()
to change it. But when the options
list changes (to a new array [“peach”, “kiwi”]), choice
automatically recomputes using the new list and becomes “peach” (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). This behavior is achieved without writing an explicit effect – the linkedSignal
internally handles the recomputation logic.
Angular provides two forms of linkedSignal
: a simple form (as above, taking just a computation function) and an advanced form that gives access to previous values of both the source and the linked signal, allowing you to implement conditional resets. For example, you could implement “preserve the user’s choice if it still exists in the new options list, otherwise fall back to default” with the advanced API. This flexibility lets you handle more complex scenarios (e.g., maintain selection if possible) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Pros:
Simplifies state management:
linkedSignal
cleanly expresses patterns that would otherwise need multiple signals plus an effect to reconcile them. It essentially combines a computed signal with a manual override in one construct (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).Avoids boilerplate: Without
linkedSignal
, one might subscribe to changes onoptions
and resetchoice
manually, or implement logic in a component lifecycle hook.linkedSignal
eliminates that boilerplate reactive glue code.Predictable behavior: It ensures
choice
is always consistent withoptions
unless deliberately set otherwise. This leads to more predictable UI state (no stale selection referencing a disappeared item, for instance).Community-driven: This feature was born from developer feedback and real-world patterns observed in apps (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). It addresses a concrete need that many have faced (the feedback thread on GitHub helped shape it (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)). Early adopters can try it and provide feedback, as it’s marked experimental in v19 (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Cons:
Experimental API: As with any brand-new feature,
linkedSignal
is in developer preview in v19 (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). The API could change based on feedback. One should use it for learning and feedback, but be prepared for possible adjustments in future Angular versions.Overuse potential: If misused, one might link too many signals in complex ways, which could become hard to follow. It’s best used for specific scenarios (like the selection pattern). For straightforward derived state that never needs override, a regular
computed
signal is sufficient.Understanding required: Developers need to grasp the nuance between a normal computed signal and a linked signal. The concept of “writable computed” is a bit advanced. Without understanding it, a dev might be surprised that their manual
set
gets overridden when the source changes. Clear documentation and training will be needed as this feature moves toward stable.
In summary, linkedSignal
is a niche but powerful addition to Angular’s reactive arsenal. It allows UIs to be more adaptive to changing data while still permitting user interaction. As one expert described, “a computed
signal is read-only, whereas a linkedSignal
is writable while preserving automatic update behavior” (What’s new with Signals in Angular 19? | Angular Newsletter) (What’s new with Signals in Angular 19? | Angular Newsletter). This makes it ideal for scenarios like form defaults, selected items, or any state that depends on another but can deviate temporarily.
New Reactive Primitives: resource()
and Async Signals
Handling asynchronous data (e.g., fetching from an API) is central to web apps. Until now, Angular developers have primarily used RxJS Observables (with HttpClient
) or resolvers/NgRX to manage async data and loading states. Angular 19 introduces the experimental resource()
API to integrate async operations into the signal reactivity model.
What it is: A Resource is a reactive wrapper for an async request + response. It ties into Angular’s change detection by treating async data as part of the signal graph. Conceptually, a resource is defined by:
A request signal or function – which can depend on other signals (e.g. an ID or query parameter).
A loader – an async function that performs the actual fetch based on the request.
The resulting resource object – which provides signals for the status (loading/error) and the value.
In practice, you call resource({ request, loader })
inside a component to create a resource.
Example: Suppose we have a userId
input signal and want to fetch a user’s profile whenever the ID changes:
@Component({...})
export class UserProfile {
userId = input<number>(); // signal input
userService = inject(UserService);
user = resource({
request: this.userId, // depends on the userId signal
loader: async ({ request: id }) => await this.userService.getUser(id)
});
}
Here, user
will be a resource that automatically triggers userService.getUser(id)
whenever this.userId()
changes (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). In the template, you can use user.value()
to get the latest loaded user (and perhaps show a spinner while user.state
is “loading”). Angular’s template can unwrap signals, so you might do something like:
<div *ngIf="user.state() === 'loading'">Loading...</div>
<div *ngIf="user.value() as u">
Hello
</div>
Under the hood, Angular tracks that userId
is a dependency of the resource. When userId
changes, the resource’s loader runs and updates the value
signal once done (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). The resource also exposes status signals such as user.state()
(could be 'loading' | 'success' | 'error'
) and possibly user.error()
if an error occurred (Angular 19 - 5 Game-Changing Features You Need to Know - DEV Community) (Angular 19 - 5 Game-Changing Features You Need to Know - DEV Community).
Angular 19’s implementation is basic but functional: on each change of the request, it calls the loader and updates the internal signals accordingly. There’s also a companion rxResource()
for bridging from Observables – you provide an Observable-returning loader, and it creates a similar resource that can emit multiple values over time (think of it like signal-based async pipe
) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). In fact, Angular v19.2 expanded rxResource
to support streaming multiple emissions, useful for cases like server-sent events or any repeated data stream (Angular 19.2 Is Now Available. And we’re back with Angular’s latest… | by Angular | Mar, 2025 | Angular Blog) (Angular 19.2 Is Now Available. And we’re back with Angular’s latest… | by Angular | Mar, 2025 | Angular Blog).
Pros:
Simplified async handling:
resource()
provides a unified pattern for loading data. It encapsulates the common needs: loading state, value, and error, without the developer writing repetitive code to manage those (no more separate “isLoading” flags, or manual subscriptions to an HTTP call) (Angular 19 features: A Know It All Guide) (Angular 19 features: A Know It All Guide).Reactive integration: Because resources are signals, they can be used in computed signals or effects seamlessly. They also integrate with Angular’s change detection – updating a resource’s underlying data triggers the component view to update just like any other signal change. This is a step toward a more signal-driven application state, reducing reliance on imperatively updating component fields after async calls.
Familiar to Angular devs: The API feels like a blend of Angular concepts (inputs, DI, HttpClient) with ideas from React Query or RxJS. Developers have commented that it “looks similar to TanStack Query… and it looks promising” (What’s new with Signals in Angular 19? | Angular Newsletter) (What’s new with Signals in Angular 19? | Angular Newsletter). It brings some of those benefits (caching, declarative data fetching) into Angular in a built-in way.
Observable interop: The inclusion of
rxResource
means you don’t have to abandon RxJS entirely. You can wrap an existing Observable (like one fromHttpClient.get()
) into a resource, getting the same loading/value signals. This eases migration since many Angular apps have an RxJS-heavy codebase.
Cons:
Experimental: Like
linkedSignal
, theresource()
API is in developer preview in v19 (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). The Angular team even opened an RFC to gather feedback and iterate on its design (Angular 19.2 Is Now Available. And we’re back with Angular’s latest… | by Angular | Mar, 2025 | Angular Blog). So you shouldn’t yet rely on it for critical production features; it might change or gain new features in the near future.Basic feature set: The initial version is relatively minimal – it covers the basics of one request = one response. Features like caching, deduplicating requests, or background refetch might not be there yet (whereas mature libraries like Apollo or TanStack Query have many utilities). You may need to implement caching logic on top of
resource
manually if needed.Learning new patterns: Angular developers not familiar with the concept of “resources” or signal-based async might need time to adjust. It’s a different style than using
async
pipe or subscribing to an HttpClient Observable inngOnInit
. Some might find it magical that callingresource()
in the constructor triggers a load automatically. Tooling and documentation will be key to help devs adopt this pattern correctly.Overlap with existing solutions: There’s some conceptual overlap with Angular resolvers (which fetch data before route activation) and with state management libraries. Teams will need to decide when to use a
resource
vs. when an NgRx effect or a simpleasync
pipe is sufficient. During the experimental phase, this might lead to some churn as best practices emerge.
Developer sentiment: Many in the community are excited about resources because it signals Angular’s commitment to a more automatic, declarative data-fetching story. It’s often seen as analogous to React’s hooks like useSWR
or Vue’s composition API for fetching data. By tying into signals, Angular’s resource could greatly simplify how we write loaders. However, seasoned Angular devs will tread carefully until the API stabilizes. It’s worth experimenting with in non-critical parts of your app to get a feel for its advantages.
The effect
API and Reactivity Evolution
In Angular 16, the effect()
API was introduced (similar to computed signals but for performing side effects). It has remained in developer preview to let the Angular team refine its behavior. In v19, Angular adjusted the timing semantics of effect
based on feedback (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog), but it remains in preview. The team is taking a cautious approach: “As a core primitive in the new reactivity, we want to take our time to get effect
’s semantics right” (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
For developers, this means you can continue to use effect
(for running code when signals change, such as updating document title or logging) but be aware that its behavior might still change slightly. No breaking changes were announced in v19, just that it’s not finalized.
Pros:
Allows imperative side-effects in a reactive way. Useful for things that aren’t directly rendered in template (for example, calling a service or updating an external library whenever certain signals change).
Feedback-driven improvements: The timing change in v19 was a direct result of developer feedback on how
effect
was working (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog), showing the API is being actively polished.
Cons:
- Not final: You might see subtle differences across versions as
effect
is tuned. For instance, the order in which effects run relative to component rendering might be tweaked.
In practice, many apps might not need a lot of effect
yet, since components themselves often handle local side effects. But as signals use grows, effect
will be important for hooking into that system. Keep an eye on future releases for when effect
becomes stable.
Component Architecture: Standalone Components and Beyond
Angular 19 pushes Angular architecture further toward a module-less, standalone component paradigm. This simplifies how we build and organize Angular apps. Alongside this, Angular 19 includes new defaults and flags to encourage best practices and modernize existing projects. Let’s explore these changes in component architecture and structure.
Standalone Components by Default
Angular’s Standalone Components (introduced in v14) allow building Angular features without NgModules, by declaring all dependencies (components, directives, pipes) at the component level. By Angular 19, this approach has proven itself – over 90% of developers in the last survey reported using standalone components (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). Now, Angular makes standalone the default mode for new components.
What changed: In Angular 19, when you generate a component (or directive/pipe) or bootstrap a new project, you no longer need to specify standalone: true
in the component’s metadata – it’s implicit. Conversely, if for some reason you need a component that is not standalone, you must explicitly mark it standalone: false
. Essentially, standalone is the norm, NgModule-based is opt-in (the opposite of old behavior) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
When you run ng update
to upgrade to v19, Angular will automatically apply a migration that:
Removes any
standalone: true
flags from your components/directives/pipes (since true is now the default) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).Adds
standalone: false
to those that were not standalone (to preserve them as NgModule-dependent) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
The CLI also updates the main app bootstrap to use bootstrapApplication(AppComponent)
(the standalone bootstrap API) if it wasn’t already. The result is a cleaner codebase with fewer boilerplate annotations.
Why this matters: This change streamlines Angular’s learning curve and project setup. New Angular developers no longer have to learn about NgModules when starting – they can add components directly. As the community has noted, “Standalone components simplify the learning curve for new developers and reduce boilerplate” (Angular 19 features: A Know It All Guide) (Angular 19 features: A Know It All Guide).
Pros:
Less boilerplate: You’ll see fewer lines in component files (one less metadata property everywhere). Application bootstrap code is also simpler.
Faster startup for newcomers: You can create components without understanding NgModule declarations. This lowers the entry barrier and gets apps running with minimal ceremony.
Modularity remains: Standalone doesn’t mean “monolithic.” You can still organize components into directories and logically separate features; you just don’t need
.module.ts
files for them.Encourages best practices: Standalone components inherently encourage more explicit dependency management (import what you need at the component), which can lead to clearer code boundaries. Also, features like tree-shakeable providers and route-based code splitting work nicely with standalone structure.
Cons:
Mixing modes: In a large existing project, you might have a mix of NgModule-based and standalone components. During migration, this can be a bit confusing. Angular does allow intermixing (you can declare standalone components in NgModules, etc.), but it’s easy to accidentally forget a
standalone: false
where needed. The newstrictStandalone
flag (below) can help enforce consistency.Third-party library compatibility: By v19 most popular libraries have added support for standalone (providing either standalone components or NgModule shims). But if any library in your stack hasn’t, you might temporarily need to keep some NgModule structure. This is increasingly rare, though.
Documentation churn: All official docs have moved to standalone-first, which might be slightly confusing if you come from an older Angular background. Terms like declarations/imports in NgModules are replaced by standalone concepts. It’s a short-term adjustment in mindset.
Overall, making standalone the default is a culmination of Angular’s modernizations. It’s widely seen as a positive step. As one article put it, “In just 2 years, standalone components went mainstream… resulting in a spike in developer experience and productivity” (Angular 19 features: A Know It All Guide) (Angular 19 features: A Know It All Guide). The Angular team themselves now follow a “standalone first” approach even in documentation and examples.
Strict Standalone Enforcement
To further encourage moving away from the old NgModule paradigm, Angular 19 adds a compiler flag that forces components in your project to be standalone. If enabled, any attempt to declare a component without marking it standalone (or any leftover NgModule-only component) will result in a compile-time error.
How to enable: In your tsconfig.json
, under angularCompilerOptions
, set "strictStandalone": true
(Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). For example:
{
"angularCompilerOptions": {
"strictStandalone": true
}
}
With this flag on, if you accidentally have a component class without standalone: true
(and without being part of an NgModule), Angular’s compiler will catch it. Essentially it disallows the old component declaration style.
Pros:
Enforces consistency: Your team can ensure no one reintroduces an NgModule out of habit. It’s especially useful in large codebases: if someone writes
@Component({ ... })
and forgets standalone, they’ll get a clear error instead of having an undeclared component floating around.Prepare for future: If Angular ever deprecates NgModules entirely, using
strictStandalone
now future-proofs your code by keeping it 100% standalone.Easy opt-in: It’s just a config change. You can even turn it on temporarily to see if any non-standalone components remain, then turn it off if you’re not ready to fully commit. (During initial upgrade, you might run with it off until after running migrations, then switch it on to catch anything missed.)
Cons:
All-or-nothing: With the flag on, you must convert every component to standalone. In a huge project with many modules, you might prefer a gradual migration. You’d keep this flag off until you’ve handled most conversions. It’s not meant for partial adoption.
Third-party declarations: If you rely on some module that declares components (rare for modern libs, but possible), enabling this flag might pose challenges. Those components would violate the rule. In practice, this is uncommon as the flag likely only checks your source, not node_modules.
Initial friction: Teams must ensure everyone knows about the flag. New components should be created standalone (which the CLI does by default now). There might be a learning moment, but beyond that it’s straightforward.
Use strictStandalone
as a tool to keep your project on the modern path. It’s especially useful once you’ve run the update schematics so that everything is already standalone/default. Think of it as similar to strict type-checking flags – it enforces a discipline that pays off in code consistency.
View Transitions for Navigation (Smooth Page Transitions)
To improve user experience, Angular 19 adds support for the new View Transitions API (available in Chrome-based browsers) in the Angular Router. This feature was actually introduced in Angular 17 and continues to be supported/improved in v19 (Check out Angular's support for the View Transitions API). It enables automatic smooth transitions between routes, like cross-fading or sliding animations, without manually writing complex animation code.
How to use: You opt-in by adding the withViewTransitions()
configuration when providing the router in your bootstrapApplication
:
import { provideRouter, withViewTransitions } from '@angular/router';
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes, withViewTransitions())
]
});
With that single change, any route navigation in a supported browser will be wrapped in the browser’s native view transition. By default, it crossfades between the old and new views. You can further customize it with CSS to achieve more elaborate animations (leveraging the platform’s capabilities). The nice thing is it works automatically for the whole app once enabled (Angular 19: Updating our projects and harnessing its latest features - DEV Community) (Check out Angular's support for the View Transitions API).
Pros:
Polished UX: View transitions give your single-page app route changes a feel closer to native apps, with smoother visual continuity. This can delight users without much dev effort.
No complex animations code: Traditionally, Angular’s router animations or custom animations require writing
@angular/animations
code and maintaining triggers. View Transitions API simplifies this by using the browser’s built-in abilities – you often just add CSS for specific elements if needed.Progressive enhancement: It only works in browsers that support it (currently Chromium-based). Browsers that don’t support it simply perform normal route changes (no harm done). So you can enable it without breaking older browsers.
Minimal performance cost: The transitions are highly optimized (being native). And if a user has prefers-reduced-motion enabled, the browser can skip or minimize the animation automatically.
Cons:
Limited browser support: At time of Angular 19, only Chromium-based browsers have the View Transitions API. Safari and Firefox may implement it later. So not all users will see the effect. (This is fine, but worth noting if you promise a design effect that some might not experience.)
Basic default transition: Out-of-the-box it does a dissolve transition. Customizing it requires understanding the View Transitions CSS (which, while easier than full animations code, is still something to learn). Complex sequences or element-level animations might still need manual work.
Not an Angular invention: This is a native platform feature; Angular just made it easy to use. Thus, its capabilities and quirks are subject to the browser’s implementation. For example, only certain CSS properties are supported in the transition, etc., which might limit what you can do compared to a fully custom Angular animation.
Enabling view transitions can immediately uplift the feel of your app. Many developers are excited about how “easy it is to add cool animations and smooth transitions” with this API (View Transitions API in Angular 17 | by Alfredo Perez | ngconf). In summary, this feature shows Angular’s commitment to integrating modern Web APIs for a better user experience with minimal developer effort.
Other Template and Component Improvements
Angular 19 includes a couple more quality-of-life changes in the template syntax and component patterns:
Local Variables in Templates: Angular templates now support declaring local variables (using the
@let
syntax) directly in the template scope. This feature was in preview in Angular 18.1 and is now stable in v19 (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). You can declare a local variable to hold intermediate calculations or values from pipes, making templates cleaner. For example:<!-- Capture an input’s value in a local var --> <input #nameInput /> @let greeting = 'Hello ' + nameInput.value; <p></p> <!-- Using with async pipe --> @let userData = user$ | async; <div *ngIf="userData as user">Welcome </div>
The
@let
syntax (note: this is the new microsyntax using@
instead of*
) allows you to introduce a variablegreeting
oruserData
for use later in the template (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). This avoids repetitive calls or deeply nested expressions. Developers had requested this for years (443 upvotes on the issue) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog), and Angular’s new template syntax design made it possible. Pros: Makes complex templates more readable; no need for hacky workarounds like using<ng-template let-x="...">
. Cons: It’s a new syntax to learn, and only works in Angular 18.1+ – but since it’s now stable, it’s a welcome addition.Untagged Template Literals in Expressions: Angular 19.2 improved template binding ergonomics by allowing backtick
`template literals`
directly in Angular expressions (Angular 19.2 Is Now Available. And we’re back with Angular’s latest… | by Angular | Mar, 2025 | Angular Blog). This helps when writing CSS class bindings or attribute bindings:<div [class]="`layout col-${colWidth}`"></div>
This is valid in Angular 19.2+, making it easier to construct strings without awkward escaping of quotes (Angular 19.2 Is Now Available. And we’re back with Angular’s latest… | by Angular | Mar, 2025 | Angular Blog). Pros: More natural JavaScript syntax in templates for string operations; you can use multi-line template strings too. Cons: Minor: older Angular versions wouldn’t support this, so ensure your project is updated if you use this syntax.
Self-closing Tags Migration: A small but nice update – Angular 19.2 introduced a schematic to auto-convert your void elements to self-closing form (e.g.
<img>
to<img/>
). While purely stylistic, this can quiet some lint rules or just align with preferences. It’s optional and doesn’t affect runtime (Angular 19.2 Is Now Available. And we’re back with Angular’s latest… | by Angular | Mar, 2025 | Angular Blog) (Angular 19.2 Is Now Available. And we’re back with Angular’s latest… | by Angular | Mar, 2025 | Angular Blog).
These enhancements contribute to a smoother development experience, making Angular templates more expressive and on par with modern standards.
Developer Tooling and Productivity
Angular 19 comes with numerous improvements aimed at making developers more productive – from build tools and Hot Module Replacement to IDE integrations and testing updates. This section covers those practical enhancements that streamline development workflow.
Hot Module Replacement (HMR) for Styles (and Templates)
Angular CLI has supported Hot Module Replacement for a while, but Angular 19 brings instant style refresh out of the box, and even experimental template HMR. This means when you update CSS/SCSS or HTML templates, the changes can be applied without a full page reload.
What’s new: In v19, style HMR is enabled by default during ng serve
(Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). If you change a component’s styles (in a .css
or .scss
file), the CLI will inject the updated styles into the page on the fly, preserving the application state. Previously, even a CSS change would cause a full reload. For templates, v19 introduces an opt-in: run NG_HMR_TEMPLATES=1 ng serve
to enable template hot-reload (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). This feature is experimental, but when active, editing an HTML template triggers the client to patch that component’s view without restarting the app.
How it works: Under the hood, the Angular CLI compiles just the changed component’s template or style, and uses WebSockets to push the update to the browser, where Angular applies it to the component (similar to React Fast Refresh or Vite HMR behavior). For styles, it’s straightforward—replace the CSS. For templates, Angular needs to destroy and re-render that component (and its children) with the new template, but it maintains the component’s state.
Usage: No config needed for style HMR (it’s automatic). To disable, you can pass --no-hmr
if needed (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). For template HMR, you currently opt in via the environment variable (as shown above).
Pros:
Fast feedback loop: Developers see CSS tweaks instantaneously, which is great for styling work. Template HMR (though experimental) can drastically cut down the wait time when adjusting HTML structure or bindings, since you don’t lose the state (e.g., form inputs or navigation state stays as is) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Improved flow: Not having to manually refresh means you stay “in the zone” while styling or making small template adjustments. The result is higher productivity and less context switching.
Opt-out available: If for some reason HMR causes an issue or you don’t want it, it’s easy to turn off per serve command (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Cons:
Template HMR limitations: Being experimental, template HMR may not catch every scenario. Some changes (like introducing a new component or structural changes) might still force a reload or could potentially mess up internal state. So you might still see reloads for bigger changes.
Stateful bugs: With HMR, the application state is retained, which is usually good – but it means if your state was in a weird condition, it persists. Sometimes a full reload is a “clean slate”. Developers might need to occasionally refresh manually to clear state if something went awry during HMR cycles.
Initial build overhead: Enabling HMR adds a tiny overhead to the dev server (for the WebSocket and update logic). It’s usually negligible, but on very large apps the HMR patch process might be slightly slower than a full reload, depending on what changed. In practice, style changes are super fast.
By shipping HMR for styles by default, Angular aligns with the experience seen in tools like webpack-dev-server, Vite, and others that developers love. It makes the development experience more fluid. One blog summarized it: “HMR allows instant edits and refresh of style or template... with no loss of state, leading to better developer experience and faster turnaround” (Angular 19 features: A Know It All Guide) (Angular 19 features: A Know It All Guide). That captures it well – it’s all about keeping your app running while you tweak it.
Angular CLI Build Improvements and Environment Variable Injection
Angular 19’s CLI received several updates that improve builds and configuration flexibility:
Faster Builds with esbuild: Angular has been working on a new build system using esbuild (called the “application” builder) to replace the old Webpack-based builder. By v19, the new builder is production-ready and can significantly speed up builds. One concrete improvement in v19 is that even unit tests run faster by leveraging this builder: you can opt-in to use the esbuild-based pipeline for Karma by setting
"builderMode": "application"
in the karma builder options (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). This can greatly improve test compile times and let tests benefit from modern optimizations (file loading, etc.). The Angular team has even deprecated Karma itself and is evaluating Jest/Web Test Runner as defaults, but in the meantime, this hybrid approach helps current Karma users get a speed boost (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).Define Environment Variables at Build Time: A top-voted feature request (350+ upvotes) was the ability to pass arbitrary environment variables to Angular at build time (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). In Angular 19, you can now use the
--define
flag withng build
to achieve this. For example:export API_KEY="abc123" ng build --define "API_KEY='$API_KEY'"
And in your app code, you could have:
declare const API_KEY: string; console.log('Building with API Key:', API_KEY);
This will replace occurrences of
API_KEY
in the code with the provided value at build time (essentially like webpack’s DefinePlugin) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). This is useful for injecting non-sensitive config (for sensitive data, you’d still use a secure runtime mechanism) or feature flags into your app without having to use file-based environment.ts for every value.Pros: It’s straightforward and flexible – you can script different build pipelines to define different values. Cons: You must take care to quote and escape properly (notice the quotes around
$API_KEY
in the example). Also, these become part of your build output (not hidden), so not suitable for secrets.Warnings for Unused Imports in Standalone Components: With the standalone component model, it’s possible to import a component or directive in the
imports: []
of a standalone component and then not actually use it. Angular 19 introduces a compiler warning for such unused imports (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). If you import a module or component that isn’t actually referenced in the template, you’ll get a warning during build/serve. This has been a highly requested feature (150+ votes) to help keep code clean (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). The Angular Language Service will also highlight these in the editor and even offer a quick fix to remove them (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). If for some reason you want to suppress this check (perhaps false positives in rare scenarios), you can set"extendedDiagnostics": { "checks": { "unusedStandaloneImports": "suppress" } }
inangular.json
(Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).Pros: Keeps your component imports tidy and minimizes bloat (unused imports might bring in unused code). Especially as we migrate to standalone, this helps catch mistakes. Cons: It’s a warning, so it won’t fail your build (unless you treat warnings as errors). In rare cases, an import might be used only implicitly (though that’s unlikely given template compilers). But you have the option to suppress if needed.
Schematics & Language Service Integration: The Angular team built an integration so that the Angular Language Service (in VS Code, for example) can run schematics (code modifications) from within your editor (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). In Angular 19, when you update the language service extension, you might get automatic suggestions to run migrations like “Convert to signal input” or “Convert query to signal” as you hover or click on code (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). This tight IDE integration means you don’t always have to remember CLI commands; the tools guide you. For example, placing your cursor on an
@Input()
and invoking the code action can apply theng generate @angular/core:signal-input-migration
for you (Angular 19: What's new - by Amos Isaila) (Angular 19: What's new - by Amos Isaila). This is a big productivity boost for developers refactoring code.Pros: Low friction updates – developers are more likely to adopt new best practices if it’s one click in their editor. Cons: You need the latest Angular language service and Angular project version for this to work. Some editors outside VSCode might not support it yet.
In summary, Angular 19’s tooling improvements revolve around speed and guidance: faster builds and tests, more flexible config, and smarter tools that gently coach you to write better Angular code. Combined, these improvements make the developer experience smoother.
Testing Updates and Future of Test Runners
Angular 19 continues the transition in Angular’s testing infrastructure: the Angular team has signaled that Karma (the traditional test runner) is deprecated and that they are evaluating alternatives like Jest or Web Test Runner as the default going forward (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). In v19, they provided a stop-gap to help Karma users in the interim: the Karma builder can run in the new “application” mode (using esbuild), as mentioned earlier, improving test build speed significantly (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
For developers: if you use ng test
with Karma, consider trying the builderMode: "application"
option. Also, keep an eye out for announcements – it’s likely that within the next version or two, Angular will officially recommend a different test setup (possibly Jest as it requires less config and runs without a browser, or some headless browser runner). In any case, Angular 19 ensures that unit tests run faster and are easier to maintain.
Pros:
Faster test feedback loop with esbuild.
Potentially easier migration to whatever new testing tool comes, since your tests themselves (written in Jasmine mostly) won’t need big changes if the runner changes.
Cons:
- If you have a complex Karma setup or custom plugins, moving to application builder might break those until you adjust configurations.
The testing story is evolving, but Angular 19 makes sure you’re not stuck with slow tests in the meantime.
Security Enhancements
Security is always a priority for Angular, and v19 introduces a developer-preview feature to help developers easily adopt a stricter security posture.
Automatic Strict Content Security Policy (CSP) Generation
The feature: Angular 19 can automatically generate a hash-based Content Security Policy (CSP) for your application’s inline scripts (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). CSP is an HTTP header that whitelists sources of content (scripts, styles, etc.) to mitigate cross-site scripting (XSS) and other injections. A strict CSP usually disallows inline scripts unless you provide cryptographic hashes for them. Angular apps often have inline scripts (like the runtime, polyfills, or Webpack bootstrap code in index.html
), which makes adopting CSP cumbersome. This new feature addresses that.
How it works: When enabled, Angular will compute the SHA-256 hashes of all inline <script>
blocks in your index.html
and emit a CSP header that includes those hashes (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). This means the browser will allow those specific scripts to run, but reject any script that isn’t known. To use it, you set "security": { "autoCSP": true }
in your build options in angular.json
(Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). Then when you serve or build the app, Angular CLI will generate a Content-Security-Policy
header (for serve) or provide the hashes for you to use in your server config (for production deployment).
Pros:
Improved security with minimal effort: You get a strong CSP without manually calculating hashes for scripts. This helps prevent attackers from injecting malicious scripts, since the browser will only run scripts whose hashes match those present at build time (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
No more unsafe-inline: Many apps resort to using
unsafe-inline
in their CSP (which basically turns CSP off for scripts) because of the difficulty of managing script hashes. AutoCSP removes that need, allowing you to keep CSP strict.Integrates with Angular CLI: It’s one flag, and it works out-of-the-box. It was developed in collaboration with security experts at Google (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog), indicating that it follows best practices.
Cons:
Developer preview: This feature is currently opt-in and in preview (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). You should test it thoroughly in your environment. It’s possible that if you have any dynamic script injections or third-party scripts, you’ll need to handle those separately (e.g., add their hashes or use nonces).
Deployment considerations: For production, Angular can output a report of hashes, but you need to actually configure your web server to send the CSP header with those hashes. During
ng serve
, it might inject headers for you, but in production, it’s up to you to apply them (perhaps via Angular Universal or a proxy config). It’s an extra deployment step to be aware of.Inline scripts still exist: This doesn’t remove inline scripts; it just secures them. Some security policies disallow any inline scripts (for example, if you’re in a very strict corporate environment). In such cases, autoCSP might not satisfy the requirement, and you’d need a different bootstrapping approach. But those cases are rare, and generally CSP with hashes is acceptable.
Enabling autoCSP
is a quick win for security-conscious apps. It reflects Angular’s philosophy of being “secure by default.” As the Angular blog states, “Using hash-based CSP, the browser will only execute an inline script if its hash is present, preventing malicious scripts from running” (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). Developers can opt in now to harden their apps, and we can expect this to become a standard part of Angular’s security toolkit in future versions.
Aside from CSP, Angular already provides robust XSS protection through its templating (automatic HTML sanitization, etc.), and Angular 19 continues to receive updates to dependencies (like DOMPurify or similar) to patch any known vulnerabilities. Always keep Angular up to date to get these security patches.
Angular Material and CDK Enhancements
Frontend developers using Angular often rely on Angular Material and the Component Dev Kit (CDK) for UI components and behaviors. Angular 19 includes notable updates in this area: a new component, better theming APIs, and improved CDK features.
New Angular Material Time Picker Component
One of the most anticipated additions, Angular Material v19 finally introduces an official Time Picker component. This addresses a long-standing gap in the component suite – previously, Material had a date picker but no equivalent time selector, forcing developers to use third-party solutions.
About MatTimepicker: The Angular Material Timepicker (<mat-timepicker>
) provides a UI for time selection, with support for multiple modes of input. It was designed with accessibility in mind and to accommodate various formatting needs. The absence of a strict Material Design spec for time pickers delayed its introduction, but community demand (1300+ upvotes on the issue tracker) pushed the team to deliver a solution that “aligns with requirements and accessibility standards” (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Features:
Configurable time increments: You can allow selecting times at specific intervals. For example, you might restrict to 15-minute increments or only on the hour. The component supports an
interval
input, e.g.<mat-timepicker interval="30m"></mat-timepicker>
for 30-minute steps (Angular Material 19 Timepicker. Angular Material 19 introduces… | by Paul Pietzko | Medium) (Angular Material 19 Timepicker. Angular Material 19 introduces… | by Paul Pietzko | Medium). Under the hood, you can specify seconds, minutes, or hours (like"60"
for 60 seconds = 1 minute,"1h"
for 1 hour steps) (Angular Material 19 Timepicker. Angular Material 19 introduces… | by Paul Pietzko | Medium). This makes it easy to enforce business rules like “appointments every 30 minutes”.Predefined time options: Alternatively, you can supply an array of specific time values with labels via an
options
input (Angular Material 19 Timepicker. Angular Material 19 introduces… | by Paul Pietzko | Medium) (Angular Material 19 Timepicker. Angular Material 19 introduces… | by Paul Pietzko | Medium). For instance, you might define presets like “Start of Business Day – 09:00” and “End of Day – 18:00” and pass those in. The timepicker will then only allow those choices. This is useful for scenarios where only certain times are valid.Multiple modes (dialog vs inline): The time picker can be used inline or as a popup attached to an input. A typical usage is similar to the datepicker: you have an
<input matInput [matTimepicker]="picker">
and a<mat-timepicker-toggle>
to open a floating time selector dialog (Angular Material 19 Timepicker. Angular Material 19 introduces… | by Paul Pietzko | Medium). It likely also supports an inline mode where the<mat-timepicker>
is always visible (for example on a settings panel).Events and two-way binding: The component emits a
selected
event when a time is chosen (Angular Material 19 Timepicker. Angular Material 19 introduces… | by Paul Pietzko | Medium), carrying the selected value. Developers can listen to this to react to changes. Also, with Angular’s two-way binding ([(ngModel)]
orFormControl
integration), it can bind to forms similarly to how datepicker works.
Basic Example:
<mat-form-field appearance="fill">
<input matInput [matTimepicker]="picker" placeholder="Select a time" [(ngModel)]="appointmentTime">
<mat-timepicker-toggle matSuffix [for]="picker"></mat-timepicker-toggle>
<mat-timepicker #picker interval="15"></mat-timepicker>
</mat-form-field>
In this example, the timepicker will let the user pick a time in 15-second increments (if interval="15"
means seconds; if minutes, it’d be "15m"). The toggle button opens the time selector popup. The chosen time is bound to appointmentTime
.
Pros:
Official support: Having an official component ensures high quality, accessibility, and regular maintenance. It also integrates nicely with Angular Material theming and form APIs.
Highly requested: Meeting a popular demand means many teams can remove their custom or third-party time pickers, reducing bundle size and increasing consistency in their app’s look and feel.
Accessibility: The Material team likely ensured the timepicker works with screen readers and keyboard navigation, which can be tricky to implement on one’s own for such a control.
Cons:
Design is new: Since Material Design didn’t have a strong spec for time pickers, some developers might find the design different from expectations (for example, some might have wanted a clock-face style picker versus maybe what Material implemented, which could be a list or wheels). Feedback will tell if the design meets most needs.
Initial version limitations: As a first release, there might be minor missing features (for instance, maybe lack of a seconds picker or limitations in internationalization). These will likely be addressed as the component matures.
Dependency on Angular Material: Obviously, if you aren’t using Angular Material, this component isn’t directly useful. But those who use other UI libraries weren’t expecting Material to solve this for them anyway.
Developers are happy to see this addition. The Angular team noted they “shipped it in v19” acknowledging the strong community ask (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). This rounds out the form controls in Angular Material, making it more comprehensive.
Material 3 Theming API Enhancements
Earlier in 2024, Angular Material moved to Material Design 3 (Material You) and introduced a new theming system based on design tokens and Sass mixins (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). Angular 19 builds on that, making the theming API more convenient and DRY.
Recap of Material 3 theming: In Material 3, you define design tokens (colors, typography, density) and use mixins to apply them to each component. For example, previously you might do:
@use '@angular/material' as mat;
@include mat.core(); // initializes theme system
$theme := mat.define-theme((
color: (
primary: mat.$indigo-palette,
secondary: mat.$pink-palette,
theme-type: light
),
typography: mat.define-typography(...)
));
@include mat.button-theme($theme);
@include mat.card-theme($theme);
// ... include mixins for every component you use
This gave you a lot of control (you could even have different palettes per component if desired), but as noted by the team, it often led to duplicate code for each component applying the same theme tokens (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
What’s new in v19: Angular Material v19 introduces a single mat.theme(...)
mixin that can apply the theme to all components in one go (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). So instead of including 20+ component mixins, you can now do:
@use '@angular/material' as mat;
@include mat.core();
$html-theme: mat.theme((
color: (
primary: mat.$violet-palette,
tertiary: mat.$orange-palette,
theme-type: light
),
typography: Roboto,
density: 0
));
html {
@include $html-theme;
}
(The exact usage might vary, but the above illustrates the idea.) According to the Angular blog, the new API allows declaring a custom theme with a single mixin mat.theme
that covers all components (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). This drastically simplifies theme setup.
Additionally, Angular 19 adds component-specific override mixins. If you want to tweak just one or two tokens for a particular component without duplicating the entire theme, you can use an override mixin. For example:
@include mat.sidenav-overrides((
'content-background-color': purple,
'container-divider-color': orange,
));
This would adjust the sidenav’s content background and divider colors to purple and orange, while keeping all other tokens (like typography, shape, etc.) as per your base theme (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). It’s essentially a partial theme for that component only, layered on top of the global theme. The overrides respect your main theme’s tokens for anything you don’t explicitly override (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Pros:
Simplified theming code: A single
mat.theme
call can replace many repetitive lines. This makes theme files shorter and less error-prone (no accidentally forgetting to include a component’s theme).Selective customization: The override API is very convenient. If your design needs the menu or sidenav to have a slightly different background than the rest of the app, you can do that with one small snippet, rather than creating an entire variant theme. It also keeps the overridden values tied to the component (making it clear what you’re customizing).
Design token flexibility: By continuing to leverage design tokens, these APIs ensure you’re still using Material 3’s power. The difference is just in ergonomics (one mixin vs many).
Backwards-compatible: If you have an existing theme using the old approach, it should continue to work. The new API likely builds on top of the same underlying system, so adopting it can be gradual.
Cons:
Sass requirement: The theming system is Sass-based. While Angular’s build supports Sass, if someone isn’t using Sass, they can’t directly use these mixins. (They’d rely on prebuilt CSS or look for CSS vars support, which Material 3 doesn’t fully provide yet for all tokens.) This isn’t new to v19, but still a constraint.
Learning curve: For those not familiar with design tokens or the Material theming approach, the introduction of yet another way (the combined mixin) might be slightly confusing at first (“Should I include individual component themes or use
mat.theme
?”). Reading the updated docs will help.Potential for misuse: If someone uses
mat.theme
and also individual mixins, they might inadvertently double-up rules. Ideally you choose one approach. The documentation likely clarifies this.
In summary, Angular Material’s theming in v19 is more expressive and DRY, addressing developer feedback about repetitive code (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). This continues Angular’s push to make Material 3 adoption easier and more flexible.
CDK Two-Dimensional Drag & Drop
The Angular CDK’s drag-and-drop utilities have been around for a while, allowing items to be dragged within a list (vertically or horizontally). Angular 19 introduces support for two-dimensional drag-and-drop, meaning you can now have free movement in both axes within a grid or similar layout (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
What it is: A new option cdkDropListOrientation="mixed"
on a drop list allows items to be moved in any direction (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). Previously, you had to specify vertical
or horizontal
. With “mixed”, the CDK doesn’t lock the movement to one axis.
Use cases: This is useful for implementing things like grid reordering or kanban boards where cards can be rearranged in both dimensions. For example, consider a dashboard where you want to let users drag widgets around a grid, or a scheduling interface where items can move in a matrix.
Example:
<div
cdkDropList
cdkDropListOrientation="mixed"
(cdkDropListDropped)="onDrop($event)">
<div *ngFor="let item of items" cdkDrag>
<mat-icon cdkDragHandle>drag_handle</mat-icon>
</div>
</div>
With cdkDropListOrientation="mixed"
, the user can drag an item and drop it anywhere in the container, not just strictly above/below or left/right (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog). The CDK will determine new ordering based on proximity. The provided snippet in the Angular blog shows cdkDropListOrientation="mixed"
and a handle on each item (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog).
Pros:
Unlocks new UI patterns: Previously, Angular devs might have had to use external libraries for full drag-drop grids. Now it’s built-in. For example, creating a reorderable photo gallery or interactive dashboards is easier.
Community-driven: This feature was a popular request (311 👍 on GitHub (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)】. Implementing it shows Angular’s responsiveness to community needs.
Familiar API: It extends the existing CDK DnD API, so if you’ve used
cdkDrag
andcdkDropList
before, you only have a small addition in options. All the same events (cdkDropListDropped
, etc.) still work.Smooth integration: Likely, the CDK handles all the tricky parts like collision detection and insertion logic. You get consistent behavior with how one-dimensional lists worked.
Cons:
Layout requirements: Mixed orientation works best when the drop list container has a consistent grid layout or known dimensions for items. If your items are of variable size, the reordering logic might not always place items exactly where you expect (though it should handle it gracefully by defaulting to some ordering algorithm). Fine-tuning might require custom callbacks to determine drop container index.
Complexity: Two-dimensional interactions are inherently more complex than a straight list. There may be edge cases (e.g., item overlaps partially between rows) that you’ll want to test. The library likely handles most of it, but as a developer you should ensure the UX is clear (maybe highlight target position, etc., for the user).
Browser performance: Drag and drop with a lot of items in a big grid could stress the browser, especially if each move triggers reflow of a complex layout. The CDK tries to be efficient (using transforms for moving items), but performance should be considered if you plan hundreds of draggable items on screen.
A real-world example of this feature: The Google Cloud Console team quickly leveraged CDK tab reordering for BigQuery (mentioned next), which indicates confidence in these new drag-drop capabilities. We can imagine similar teams will use 2D dragging for rearrangeable UIs.
CDK Draggable Tab Reordering
Angular 19 also adds support for tab reordering in the CDK, which was another feature request (24 👍, smaller but specifi (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)3】. This allows a set of tabs (like in a tab group) to be made draggable so users can reorder them via drag-and-drop.
While Angular Material’s <mat-tab-group>
doesn’t natively support reordering via drag, the CDK provides the building blocks to implement it. The new addition likely provides either a directive or pattern to make a list of tabs (<div cdkDropList>
with tab labels as cdkDrag
) work nicely with the tab content.
The Angular blog highlights that the BigQuery team in Google Cloud Console **immediately used this feature to allow users to drag tabs around in their UI (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)3】. This suggests the API was effective and straightforward to integrate.
Pros:
Improved user experience: Users expect to be able to reorder tabs (like we do in browsers or code editors). Now Angular apps can offer that feature easily.
Consistent with Material Design: While Material Design spec doesn’t explicitly talk about draggable tabs, it’s a common UX pattern. Implementing it via CDK means you can style it as needed (for example, a shadow or outline of the tab as you drag).
Leverages existing CDK DnD: Under the hood, it’s probably using the same mixed-orientation or horizontal DnD logic, just tailored to tablist semantics.
Cons:
Manual wiring: Until Material TabGroup perhaps integrates this, developers will have to wire it up using CDK directives on the tab headers container. It’s a bit of work (but much less than writing DnD from scratch).
State management: If tabs correspond to some state (like route order or some config), the developer needs to update that state on drop. The CDK will tell you the new order, but you must apply it to your data (e.g., rearrange an array of tab items). Minor consideration, though.
Overall, the CDK continues to empower Angular devs to create modern, interactive interfaces without needing external libraries. These enhancements in Angular 19 (2D drag, tab reorder) show a maturity in the CDK module that covers many advanced UI scenarios.
Migration Strategies for Upgrading to Angular 19
Upgrading to Angular 19 is generally straightforward thanks to the Angular CLI’s ng update
tool and the numerous schematics provided to automate code changes. Here’s a breakdown of how to approach the upgrade and take advantage of the new features, especially if coming from Angular 15-18:
Using ng update
to Upgrade Core and CLI
First, update your project’s Angular packages by running:
ng update @angular/core @angular/cli@19
This will install Angular 19 and run the necessary migrations. Key automated migrations include:
Standalone Default Migration: The update will execute a schematic (internally or via a separate step) to adjust component metadata for the new standalone default. All components, directives, and pipes that were standalone will have their
standalone: true
removed (since true is now default), and any that were not standalone will getstandalone: false
add (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)2】. This ensures your code’s behavior remains the same after the update. The schematic might be calledexplicit-standalone-flag
(as noted in some documentatio (Angular 19: What's new - by Amos Isaila) (Angular 19: What's new - by Amos Isaila)1】, and it essentially makes the implicit things explicit where needed. After this, you can optionally remove thosestandalone: false
flags once you’re ready to fully embrace standalone everywhere (or keep them – they don’t hurt).Bootstrap Migration: If your app was using
NgModule
for bootstrap (withplatformBrowserDynamic().bootstrapModule(AppModule)
in main.ts), the update might offer to switch it to the newbootstrapApplication(AppComponent)
approach. If it doesn’t automatically, you can do this manually or use theng generate @angular/core:standalone
schemat (Angular 19: Updating our projects and harnessing its latest features - DEV Community) (Angular 19: Updating our projects and harnessing its latest features - DEV Community)1】, which can migrate an existing app to standalone bootstrap, including converting the AppModule to just register providers and then bootstrap the AppComponent directly.Injectable Constructor to inject() Migration: Angular 19 provides an optional migration to transform constructor-based DI in certain classes to use the new
inject()
function. This isn’t applied by default on update, but you can invoke it via: `ng generate @angular/core:injec (Angular 19: Updating our projects and harnessing its latest features - DEV Community)9】. This would convert patterns like:constructor(private service: SomeService) {}
into
private service = inject(SomeService);
inside the class (and remove the constructor if it was empty otherwise). This is somewhat style/preference, but using
inject()
in non-component classes (like plain services, or standalone functions) can be beneficial. It’s up to you if you want to run it; it’s not mandatory.Lazy Loading Routes Migration: Another optional but useful schematic is
ng generate @angular/core:route-lazy-loadin ([Angular 19: Updating our projects and harnessing its latest features - DEV Community](https://dev.to/dimeloper/angular-19-updating-our-projects-and-harnessing-its-latest-features-3ppm#:~:text=In%20version%2019%20we%20also,routes%20to%20lazy%20loaded%20routes)) ([Angular 19: Updating our projects and harnessing its latest features - DEV Community](https://dev.to/dimeloper/angular-19-updating-our-projects-and-harnessing-its-latest-features-3ppm#:~:text=ng%20generate%20%40angular%2Fcore%3Ainject%20ng%20generate,loading))0】. This will scan your
RouterModule.forRoutesdefinitions and convert any routes that lazy-load components (i.e., have
component: SomeComponentwhere SomeComponent is a heavy component) into lazy loaded routes using
loadComponent. This was introduced in v14+ as a way to lazy load at component level. The schematic will replace
component: XYZComponentwith
loadComponent: () => import('.../xyz.component').then(m => m.XYZComponent)` for those you want to lazy load. Use with caution: By default it might convert all, but you may not want every route to lazy load (some simpler ones can stay eage (Angular 19: Updating our projects and harnessing its latest features - DEV Community)7】. It’s optional – you choose to run it or not.Cleanup Unused Imports: The CLI can remove unused standalone imports project-wide via `ng generate @angular/core:cleanup-unused-import (Angular 19: Updating our projects and harnessing its latest features - DEV Community) (Angular 19: Updating our projects and harnessing its latest features - DEV Community)0】. This complements the warning feature by proactively deleting them. Always double-check the git diff to ensure nothing needed was removed, but in theory it only removes imports that aren’t used in any template.
Signal Inputs/Outputs Migration: Perhaps the biggest new change is the signals. Angular provides schematics for those too, but they are not run by default (since not everyone is ready to switch). You can manually run:
-
ng generate @angular/core:signal-input-migration
– converts@Input()
toinput()
cal (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)0】. -
ng generate @angular/core:signal-queries-migration
– converts@ViewChild
/@ViewChildren
(and content child queries) toviewChild()
etc. -
ng generate @angular/core:output-migration
– converts@Output()
EventEmitters to the newoutput()
function.
Or simply run
ng generate @angular/core:signals
to do all the above in one (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)0】. This is optional but recommended if you want to fully embrace the new reactive primitives. The migration will handle most cases automatically. For instance, an@Input() count = 0;
might becomecount = input<number>(0);
. It will also update references in the component class to callcount()
if needed. Important: After migration, any place where you were setting an @Input from within the component will need adjustment (sincecount
is now read-only). The migration can’t fully know your intent there, so you might need to refactor such logic (perhaps by turning that input into a regular signal or so). Tests can help catch any issues.Initial reports from developers who tried the signal migrations are positive, with many inputs/outputs converted automatical (What’s new with Signals in Angular 19? | Angular Newsletter)5】. It’s a huge time-saver compared to manual refactoring.
-
Other Minor Migrations: The changelog also mentions a migration for self-closing tags (if you wan (Angular 19.2 Is Now Available. And we’re back with Angular’s latest… | by Angular | Mar, 2025 | Angular Blog)5】 and possibly forms (adding support for Set in FormControl, but that likely doesn’t need a migration unless strict types). These are edge cases.
After running ng update
and applicable schematics, run your tests and linting. The update should preserve behavior. If strictTemplates
or other compiler options are on, you might encounter new warnings (like the unused imports warnings, or perhaps stricter type checks). Address those as needed (the Angular update guide on update.angular.dev will list any breaking changes, but Angular 19 is a relatively smooth update).
Post-Update: Taking Advantage of New Features
Once on Angular 19, you can gradually adopt new features:
Enable Strict Standalone: If your project is now fully using standalone components (no old NgModule patterns left unconverted), consider turning on
"strictStandalone": true
intsconfig.json
to enforce (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)2】. This will ensure new code stays in the standalone style. If you hit any errors, it means something wasn’t converted – fix those or disable if not ready.Opt-in to Incremental Hydration: If you have an SSR setup, you might want to experiment with incremental hydration. Ensure you’ve updated to use
provideClientHydration()
in main.ts (this might have been set up if you created the project with SSR recently). Then addwithIncrementalHydration()
as shown earlier. Apply@defer
where appropriate in your templates to test lazy hydration. Because it’s a preview feature, do this in a staging environment and measure performance. You can always removewithIncrementalHydration()
if you encounter issues, falling back to full hydration.Use Route Config for SSR: If you have an Angular Universal (SSR) app, try out the new route-level rendering config. Create a
server.routes.ts
file (or similar) and define yourServerRoute[]
. Integrate it by providing it in your server app module (or whatever configuration Angular Universal expects – check the docs for how to hook it in; likely something like adding it toprovideServerRendering()
options). Test that the routes behave as expected (e.g., a route set to client-only should not be pre-rendered). This is optional but can improve performance if used wisely.Adopt Signals in Components: Start using
signal
,computed
,effect
in your new component code where appropriate. For state that was previously viaBehaviorSubject
or stored in component fields with manual change detection, you can try signals. Angular 19’s stable signals (for inputs/outputs) means you can use them freely. For asynchronous data, try outresource()
. Perhaps convert one or two data fetching services to useresource()
and see how it simplifies your component logic. Keep in mindresource
is experimental, so maybe wrap it in a feature flag or use in non-critical path initially.Update Angular Material Styles: If you use Angular Material and had a custom theme file, refactor it to use the new
mat.theme
mixin. It’s not required, but it can greatly simplify your styles. Also, explore the new component override mixins for any custom tweaks you did via deep CSS or other hacks; you might replace those with first-class theme overrides. This will make maintenance easier going forward.Replace Third-Party DnD/Timepickers: If you used a third-party library for time picking (like ngx-timepicker or similar), evaluate switching to the official
<mat-timepicker>
. It provides a consistent user experience with the rest of Material components. Also, if you wrote custom drag-and-drop logic for grids or tab reordering, consider replacing it with CDK’s implementation to reduce custom code. Test these thoroughly to ensure feature parity.Turn on autoCSP in dev: If security is a concern for your app, try enabling
autoCSP
during development (ng serve
). Check the console or network headers to see the generated CSP. You might see something likeContent-Security-Policy: script-src 'sha256-abcdef...' 'sha256-ghijkl...';
etc. Make sure all your scripts are accounted for (if you dynamically add any, those wouldn’t be hashed). Then implement that header on your production server. This might require configuring your web server or cloud hosting to include the header.Testing adjustments: If you use Karma, set
builderMode: "application"
inangular.json
for the test builder as mentioned. Your tests should run faster. Keep an eye on Angular’s announcements about the future default test runner; you might consider migrating to Jest ahead of time. Angular 19’s experiments with Jest support (there was experimental support added in v16) means you could try switching now. But if not, the Karma improvements in 19 have you covered for the time being.Developer education: Ensure your team is aware of the changes. For example, they should know that
@Input()
is now often a signal (so calling it as function), and that standalone is default (so don’t addstandalone: true
anymore). This can be done via a team meeting or documentation. Emphasize the pros of the new approaches (as we detailed). Perhaps update any internal style guides to align with Angular 19 conventions.
Backward Compatibility and Potential Pitfalls
Angular 19 is backwards compatible with Angular 16-18 code for the most part. The deprecated stuff (like ViewEngine) has long been removed by v16, so as long as you were on Ivy, you’re fine. A few things to note:
If you were using Zone.js-specific logic, be aware that zone-less is optional. Angular 19 still includes Zone.js by default. You don’t have to remove it. But if you choose to try zone-less, obviously any code relying on
NgZone
or zone-stable events might need refactoring (e.g., calls tozone.run()
become no-ops).The Angular Package Format changed in v16 to remove UMD bundles and such. By v19 all libraries should be publishing Ivy-native code. If you have a library that wasn’t updated since v12 or so, that could be an issue (but then it would have been an issue in v16 too). Generally, library compatibility is high if they kept up.
Forms changes: Angular 14-15 had some strict typing changes for forms. In v19, they added support for
Set
as a value inFormControl
(for multi-select perhaps). This is a non-breaking addition, but if you have your own form value accessors, consider if supporting Set is needed.Localization: Angular 18 introduced a new hydration of i18n maybe, but no major changes in 19 that I’m aware of. Just test if you use Angular i18n.
ESM and Node versions: Check the Angular 19 compatibility notes for required Node version and TypeScript version. Usually, Angular bumps to a newer TS. Angular 19 might require TS 5.2 or 5.3 (not sure exact) – the update will handle that. Ensure your IDE is using the matching TS version to avoid weird errors.
Deprecations: Karma is deprecated as mentioned, but still works. The old
@angular/platform-webworker
was deprecated long ago (no one likely uses it now). Just be aware of deprecation warnings in your console and plan accordingly in future updates.
Migration Table: Common Old vs New Patterns
Aspect
Angular 18 and earlier
Angular 19 New Approach
Component registration
NgModule
with declarations
array, or standalone with standalone: true
.
Standalone by default (no NgModule needed). Non-standalone must be explicitly `standalone: fals ([Meet Angular v19. In the past two years we doubled down…
Bootstrap
platformBrowserDynamic().bootstrapModule(AppModule)
bootstrapApplication(AppComponent)
(Standalone bootstra (Angular 19: Updating our projects and harnessing its latest features - DEV Community) (Angular 19: Updating our projects and harnessing its latest features - DEV Community)3】.
Inputs
@Input() data: Type;
(property)
data = input<Type>();
(signa (Angular 19: What's new - by Amos Isaila) (Angular 19: What's new - by Amos Isaila)0】. Template binding unchanged (auto unwraps).
Outputs
@Output() changed = new EventEmitter<Value>();
changed = output<Value>();
(emits signals/observables). Usage in parent template remains (changed)="..."
.
ViewChild/ViewChildren
@ViewChild(Something) comp?: Something;
comp = viewChild(Something);
which is a signal yielding the child instance. Access via comp()
.
Two-way binding (NgModel)
Uses [(ngModel)]
which under the hood uses an NgModel
directive and @Output()
/@Input()
.
Can use the new model()
in a component for a form control state as a signal. Angular also introduced @angular/forms
integration but unchanged in 19.
Lazy route
component: SomeComponent
(eager load component code)
loadComponent: () => import('...').then(m => m.SomeComponent)
to lazy load component. (Possible via schematic)
Hydration (SSR)
Full hydration only (Angular 18 had event replay opt-in)
Incremental hydration (with @defer
) and event replay on by defau ([Meet Angular v19. In the past two years we doubled down…
Route configuration (SSR)
No built-in per-route control (all SSR or all prerender by convention)
Use ServerRoute
config with RenderMode
for each rou ([Meet Angular v19. In the past two years we doubled down…
Zone.js
Required for change detection (unless using 18’s exp. feature)
Optional experimental zone-less mode (`provideExperimentalZonelessChangeDetection() ([Meet Angular v19. In the past two years we doubled down…
Content Security Policy
Developer manually writes CSP (often with unsafe-inline
due to Angular scripts)
autoCSP: true
to auto-generate hash-based CSP for inline scrip ([Meet Angular v19. In the past two years we doubled down…
Styles HMR
CSS changes trigger full reload
CSS changes patch live without relo ([Meet Angular v19. In the past two years we doubled down…
Template HMR
HTML changes trigger full reload
Experimental live reload of templates (no state loss) with env fl ([Meet Angular v19. In the past two years we doubled down…
Time Picker
No official component (use third-party or HTML <input type="time">
)
Use <mat-timepicker>
from Angular Material v ([Meet Angular v19. In the past two years we doubled down…
Material theming
Include each component’s theme mixin individually
Use unified mat.theme()
mixin for a ([Meet Angular v19. In the past two years we doubled down…
Drag & Drop
1D lists via CDK; limited tab drag support
2D drag (mixed
orientation) and tab reordering via C ([Meet Angular v19. In the past two years we doubled down…
Testing
Karma default, slower builds
Karma can use builderMode: application
for spe ([Meet Angular v19. In the past two years we doubled down…
This table should help identify what changes to make during migration. Many are optional – your app will run without adopting signals or new DnD, but embracing them can yield benefits.
Community Tips and Sentiments on Migrating
The community has been largely positive about Angular 19. Many appreciate that Angular continues to evolve while providing migrations to keep apps up-to-date automatical (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)2】. Some tips and sentiments shared by developers:
Leverage the schematics: “CLI migration scripts (via
ng generate
) should be your first stop. I ran the signal input migration and hundreds of inputs were updated seamlessly, including the templates!” – This kind of feedback (from a Reddit discussio (How to start introducing signals? : r/Angular2 - Reddit)4】 reinforces using the provided tools rather than doing things by hand.Test thoroughly after each migration: While the automated migrations do a lot, it’s wise to run unit tests and e2e tests to catch any subtle changes. For example, after converting to signal inputs, test that parent-child communication still works as expected.
Incremental adoption: “You don’t have to rewrite everything to signals on day one. Focus on new development with signals and gradually refactor older parts if/when convenient.” Many experts suggest a gradual approach. Angular 19 is perfectly happy if you use a mix of old and new patterns (except you should avoid mixing standalone and NgModule in the same feature – better to convert feature by feature).
Stay informed via official guides: The official Angular Update Guide (update.angular.dev) provides step-by-step guidance tailored to your current version and additional usage (like if you use Angular Universal, etc.). Always read that – it may mention specific small changes. For v19, one change mentioned is that the default TypeScript target might have been raised (which could drop support for really old browsers unless you polyfill). Small things like that could be noted there.
Community packages: Check that any critical third-party Angular libraries you use have a v19 compatible release. Most Angular libraries that worked on v16-18 will work on v19 without changes (thanks to Ivy stability). But if a library provides schematics or has peerDependencies, you might need to update it. For example, if you use NgRx, ensure you update to the latest NgRx which likely adds support for Angular 19 (NgRx v16, etc.). The Angular Update Guide usually lists known incompatible packages if any.
Enjoy the improvements: A community blog commented, *“Angular 19’s features transform the development experience – everything feels a bit faster and cleaner. (Angular 19 features: A Know It All Guide) (Angular 19 features: A Know It All Guide)0】 Indeed, after migrating, developers report that their apps are not only on a newer version but also improved in code quality (due to the migrations that apply best practices). Embrace those changes as an opportunity to clean up technical debt (like removing old modules, simplifying code with signals, etc.).
Keep an eye on future deprecations: Angular 19 sets the stage for Angular’s future (like zone-less and possibly signal-based Angular Router in the future). While migrating, take note of anything that’s marked deprecated in console. For instance, if you see warnings about some old API usage, consider replacing it now if possible rather than later.
By following these strategies, you can upgrade to Angular 19 confidently. The Angular team’s focus on automated migrations and backward compatibility makes the process much easier than framework upgrades of the past. Once on v19, you’ll be well-positioned to take advantage of the improved performance, cleaner code, and new capabilities in your Angular applications.
Sources:
Minko Gechev – “Meet Angular v19” (Angular Blo (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)7】
Angular Dev Documentation – *Incremental Hydration Guid (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)7】
Angular Dev Documentation – *Route-Level Render Mode (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)2】
Angular Blog – Angular 19.2 Release (Template literal suppor (Angular 19.2 Is Now Available. And we’re back with Angular’s latest… | by Angular | Mar, 2025 | Angular Blog) (Angular 19.2 Is Now Available. And we’re back with Angular’s latest… | by Angular | Mar, 2025 | Angular Blog)7】
Rajat Gupta – “What’s New in Angular 19” (Mediu (What’s New in Angular 19: Key Features and Updates | by Rajat Gupta | Medium) (What’s New in Angular 19: Key Features and Updates | by Rajat Gupta | Medium)1】
Alain Chautard – Angular Training Newsletter (Signals in v1 (What’s new with Signals in Angular 19? | Angular Newsletter) (What’s new with Signals in Angular 19? | Angular Newsletter)5】
Angular Blog – *“Try Out the New Signal Input Migrations (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Angular 19: What's new - by Amos Isaila)3】
Angular Blog – *“Secure Applications with Strict CSP (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)9】
Angular Blog – *Angular Material v19 Feature (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)3】
Angular Blog – *CDK Drag&Drop mixed orientatio (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)8】
Angular Blog – *BigQuery draggable tabs (CDK tab reorder (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog) (Meet Angular v19. In the past two years we doubled down… | by Minko Gechev | Angular Blog)3】
Dev.to – “Angular 19: Updating our projects and harnessing its latest features” (Dimitris Kiriakaki (Angular 19: Updating our projects and harnessing its latest features - DEV Community) (Angular 19: Updating our projects and harnessing its latest features - DEV Community)2】
Kellton Tech Blog – *“Angular 19: New features and updates for developers (Angular 19 features: A Know It All Guide) (Angular 19 features: A Know It All Guide)2】
Angular Changelog – *Official Angular 19 Changelog on GitHu (Angular 19.2 Is Now Available. And we’re back with Angular’s latest… | by Angular | Mar, 2025 | Angular Blog)6】 (for self-closing tags, etc.)
Date: