Even if you haven’t migrated to Signals, you may still be able to make your app zoneless. Angular 17.1, which brings Signal Inputs, is slated for mid-January.
Project Plan for Reactivity/Signals
The Angular team has laid out its roadmap for the Signals/Reactivity initiative, offering a detailed view of the tasks in progress and upcoming milestones.
https://github.com/orgs/angular/projects/31
Zoneless without Signals
A significant reveal from the plan is that developers will be able to achieve zoneless apps even without first adopting Signals—something many might have assumed impossible.
This comes as a major relief for teams with large, established codebases, where a full Signals migration would be a multi-year effort.
Going forward, a zoneless setup will require the OnPush change detection strategy. Previously, zone.js handled the detection of DOM events and async operations. In a world without zone.js, the markForCheck method becomes responsible for directly invoking change detection.
This method already runs automatically alongside handled DOM events, the async pipe, and immutable property binding updates. However, for other scenarios—such as async tasks—you'll need to call markForCheck yourself by injecting the ChangeDetectorRef.
Adopting Signals provides the other path forward.
It's also worth noting that combining zoneless mode with OnPush hinges on a fresh scheduler, a piece that hasn't been introduced yet.
Signal Inputs
Angular 17.1, due in mid-January, is set to introduce Signal Inputs. These replace the @Input decorator with a straightforward input() function. The return value is a Signal, making it straightforward to consume within a computed or effect.
Either a generic type or a default value is expected by the input function. In cases where no default is provided, the returned type becomes a union of undefined and the declared type. A required option exists as well, which removes undefined from the type but triggers a runtime error when the value is absent.
A cleaner codebase results from Signal Inputs. A computed or effect suffices, removing the need for ngOnChanges.
#1 Initial PR for signal inputs
#53521
Check the individual commits for details.
This change adds signal inputs to components that still rely on Zone.js. It marks an incremental move toward making signal inputs available to the wider Angular ecosystem sooner.
With this, developers get early access to signal inputs while we finish building out fully signal-based components as laid out in the RFC. This gives the community a chance to adopt signals in greater depth, gear up for upcoming migrations, and see tangible gains in code quality and developer experience—particularly for components using OnPush.
Our experience building full signal components has taught us a lot and shifted our approach. The API now includes a more intuitive syntax for marking inputs as required, plus refinements for handling initial values. As a bonus, the input function now accepts complex values as its first argument.
@Directive({..}) export class MyDir { firstName = input<string>(); // string|undefined lastName = input.required<string>(); // string age = input(0); // number
Technical notes When working with Zone components, be aware that signal inputs deviate from the semantics laid out in the RFC. They are not classified as "computeds". In practical terms, these inputs refresh exclusively during change detection cycles. This behavior should not be conflated with how full signal components handle inputs as computations, as described in the RFC.
For component inputs, developers can choose between the traditional @Input decorator and the input() function that produces signal inputs. This dual approach is designed to smooth the transition toward signal-based patterns. However, this hybrid support is not intended for full signal components. Consider the following example:
// Both of these are valid in the same component age = input(); @Input() name = '';
Following our feedback on the RFC-proposed API, we've fine-tuned the signature of inputs. A technical constraint rendered the original design—where the initial value could double as the first parameter—unworkable. This difficulty traced back to complications in static analysis and hindered progress toward future single-file builds. Beyond that, these adjustments opened up additional advantages, which we have detailed earlier.
