Skip to content

Feature request: public component-scoped render timing hooks (beforeEveryRender) #68788

@ronnain

Description

@ronnain

Which @angular/* package(s) are relevant/related to the feature request?

core

Description

Angular already exposes afterEveryRender and afterNextRender, but these hooks are application-wide and post-render only.

This makes them useful for DOM work, but not sufficient for measuring how long a specific component rerender takes from a reusable abstraction such as a plain function or a provider.

Today, render timing can be measured when the logic is written directly inside a component class using lifecycle methods, but this does not compose well when the monitoring logic lives in:

  • a reusable function
  • a provider
  • a shared library utility

For example, this kind of API would be very useful:

function monitoring() {
  let start: number | null = null;

  beforeEveryRender(() => {
    start = performance.now();
  });

  afterEveryRender(() => {
    console.log('every render', performance.now() - start!);
  });
}

@Component({
  selector: 'app-child',
  template: `
    <br />Child Counter<br />
    <button (click)="counter.set(counter() - 1)">--</button>
    <span> Counter: {{ counter() }} </span>
    <button (click)="counter.set(counter() + 1)">++</button>
  `,
})
export class Child {
  _ = monitoring();
  counter = signal(0);
}

The issue is that:

  • there is currently no public beforeEveryRender
  • afterEveryRender is not component-scoped
  • ngDoCheck is only available as a class lifecycle method

This kind of monitoring becomes especially valuable when a lot of code is produced or iterated on through high-level abstractions, code generation, or AI-assisted workflows. In those cases, having a simple and reusable way to observe component render cost provides a fast feedback loop for detecting latency caused by poor composition patterns, or suboptimal architectural choices.

It would also be valuable in production, especially when users report latency that cannot be reproduced locally or with test datasets. A stable component-scoped timing API would make it possible to emit alerts through existing monitoring systems when specific components exceed expected render thresholds, allowing teams to investigate and mitigate regressions before they become widespread user-facing issues.

Proposed solution

Expose a public component-scoped before-render API that can be paired with afterEveryRender.

There are two possible ways to expose it:

Option 1: beforeEveryRender

A direct hook that mirrors afterEveryRender, but runs before rendering starts for the current component scope.

function monitoring() {
  let start: number | null = null;

  beforeEveryRender(() => {
    start = performance.now();
  });

  afterEveryRender(() => {
    console.log('every render', performance.now() - start!);
  });
}

Option 2: BeforeRenderRef

An injectable API that allows registering before-render callbacks from reusable abstractions.

function monitoring() {
  let start: number | null = null;
  const beforeRenderRef = inject(BeforeRenderRef);

  beforeRenderRef.every(() => {
    start = performance.now();
  });

  afterEveryRender(() => {
    console.log('every render', performance.now() - start!);
  });
}

It would be especially useful if BeforeRenderRef was also accessible from component providers, so monitoring and instrumentation patterns could be customized through DI without requiring code directly inside the component class.

This would make it possible to build:

  • component performance monitoring utilities
  • reusable instrumentation helpers
  • provider-based diagnostics
  • render timing abstractions that work in production
  • library-level tooling without depending on internal Angular profiler APIs

Alternatives considered

One workaround today is to rely on Angular's internal profiler hooks, which are also used by the Chrome DevTools integration.

Angular already emits internal profiling events around template updates, so the framework clearly has access to the right timing boundaries internally.

However, this is not a viable public solution because:

  • it relies on internal profiler APIs
  • it is dev-oriented
  • the practical integration is tied to Chrome DevTools profiling
  • it is not exposed as a stable public API for application or library code
  • it is not available as a supported production-friendly component-scoped abstraction

Another partial alternative is to keep using class lifecycle methods such as ngDoCheck, but that does not work well for reusable abstractions built as plain functions, providers, or shared instrumentation helpers.

As a related observability feature, it would also be useful to expose a component's current inputs through an injection token. I would not need the returned value to be strongly typed. Access to the current input values would already be useful for logging the component state into a monitoring system whenever a latency spike or bug is detected.

That would make it easier to correlate:

  • slow renders
  • runtime errors
  • the component input state that triggered them

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: coreIssues related to the framework runtimefeatureLabel used to distinguish feature request from other issues

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions