What does calling Angular's enableProfiling() from @angular/core add to a Chrome DevTools Performance recording, and why call it before bootstrapApplication()?
answer
- custom track beside the main thread
- framework names instead of minified functions
- startup is captured only if early
- development mode only
- count the synchronization passes
basics
~20 senableProfiling() sends Angular's own events to Chrome's Performance panel as a custom Angular track (bootstrap, change detection cycles, components, template updates, hooks, DI creation), correlated with the main thread; calling it before bootstrap captures startup too.
solid answer
~40 s`enableProfiling()`, public API since v21, routes Angular's internal profiler events into Chrome's Performance panel through the DevTools extensibility API. A recording then has a separate **Angular** track next to the usual main-thread data: bootstrap, each change detection cycle and its synchronization passes, component processing, template create and update, host bindings, lifecycle hooks, template event listeners, DI instance creation and defer block state changes, all named in framework terms. That tells you whether a long task is your Angular code, layout and paint, or another script on the page. Called before `bootstrapApplication()` it also captures startup; `ng.enableProfiling()` in the console works for a running app. It only works in development mode (a no-op in production) and returns a function that stops the profiling.
code
ts · 11 linesimport { enableProfiling } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { App } from './app/app';
// Enable before bootstrap so startup events reach the Angular track.
const stopProfiling = enableProfiling();
bootstrapApplication(App).catch((err) => console.error(err));
// Later, if you only want one scenario captured:
// stopProfiling();go deeper
Recall that enableProfiling() adds an Angular track to Chrome's Performance recordings and only works in development mode.
Explain what the track contains, why it is called before bootstrap, and how ng.enableProfiling() covers a running app.
Use the track to separate Angular work from layout and third-party scripts, and read extra synchronization passes as state changing during a check.
Decide how teams share traces with the Angular track as the common evidence format for performance reviews and bug reports.
## The gap it fills Chrome's **Performance panel** records everything on the main thread: scripts, style calculation, layout, paint. In an Angular app, much of the scripting shows up as generic framework function names, and it is hard to map a long task back to "the `ProductList` template update during the third change detection cycle". `enableProfiling()`, exported from `@angular/core` and public API since v21 (the integration first shipped in v20), closes that gap. It subscribes to Angular's internal **profiler events** and forwards them to Chrome through its **extensibility API**, which lets a page add custom tracks to a recording. ## What appears in the recording With the integration on, a recorded profile contains two correlated data sets on separate tracks: - the **standard browser entries** (main thread, network, frames); - a custom **Angular** track contributed by the framework runtime. The Angular track names its entries in framework terms: | Entry | What it marks | |---|---| | Bootstrap application / component | Startup of the app and its root component | | Change detection *n* | One full change detection cycle | | Synchronization *n* | A pass within that cycle that traverses views | | Component name | Processing of one component | | `<template>` (create) / (update) | Template creation or binding update | | HostBindings | Host binding evaluation | | `Component:ngOnInit` and other hooks | Lifecycle hook execution | | Listener function name | A template event or output listener running | | Provider token name | An instance created by an injector | | Defer block | A `@defer` block changing state | Entries use different colours to separate kinds of work, such as framework entry points, developer-written code and compiled template code. ## Enabling it There are two ways to turn it on: 1. **In startup code**: import `enableProfiling` from `@angular/core` and call it before `bootstrapApplication()`. The events for bootstrap, root component creation, the first change detection and the services created during startup are emitted as they happen, so enabling it later misses them. 2. **From the console**: in a development build, `ng.enableProfiling()` turns it on for a running app, which is enough for profiling a later interaction. Details that matter: - It works **only in development mode**; in production it does nothing. - It **returns a function** that stops sending profiling data, useful when you want to limit the overhead to one scenario. - It is **Chromium-specific**, because it relies on Chrome's Performance panel extensibility. ## How to read it Three questions the track answers quickly: - **Is it Angular at all?** When a long task on the main thread has no matching entries on the Angular track, the time belongs to layout, paint or another script on the page, and optimizing components will not help. - **Which component and which phase?** The nesting under a change detection entry shows which component's template update or which hook consumed the time. - **How many synchronization passes did one cycle need?** More than one suggests state was updated during change detection, which slows updates and in the worst case loops. Since v22.1 a component entry's summary can link into the Angular DevTools extension's Components tab to inspect that component, provided the extension is installed and an experimental Chrome flag is enabled. ## Common mistakes - **Enabling it after the slow part happened.** A call from the console only affects events after the call; to see startup, it must run before bootstrap. - **Profiling a production build.** Nothing appears on the Angular track, because the function is a no-op there; the empty track is not evidence that Angular was idle. - **Reading only the Angular track.** Its value comes from the correlation with the main thread; a long frame dominated by style and layout work is a different fix from a long template update. - **Leaving it running for long sessions.** Every event becomes a trace entry, which adds overhead in the development build; the returned stop function lets you limit capture to the scenario you care about. ## Where it sits next to Angular DevTools The Angular DevTools **Profiler** gives a focused view of change detection cycles and component times. `enableProfiling()` puts the same framework vocabulary **inside** the browser's full trace, so you can see Angular's work alongside layout, paint and third-party scripts on one timeline. Use the Profiler to find the slow component quickly; use the Chrome track when you need to know how that work sits within the whole frame.
- A long main-thread task shows no entries on the Angular track. What does that tell you?That the time was not spent in Angular's own bootstrap, change detection, templates, hooks or DI during that task. It is more likely layout, paint or another script on the page, so the next step is the standard main-thread data rather than component optimization.
- Why can enableProfiling() stay in main.ts without slowing production?Its implementation checks development mode and, in production, registers nothing and returns an empty stop function. The profiler hooks it attaches exist only in development builds.
saying these in an interview costs you the question
- enableProfiling() also records Angular events in production builds
- It replaces the need for the browser's main-thread data
- Calling it after bootstrap still captures application startup
- It is an Angular DevTools extension setting, not a core API
- One change detection cycle always has exactly one synchronization pass