In Vue 3, what does setting app.config.performance to true do, and where do you see its output?
answer
- User Timing marks and measures
- named after the component
- init, render, patch, mount
- development builds only
basics
~20 sapp.config.performance makes Vue write User Timing marks and measures for each component's init, compile, render, patch and mount. You see them as named timings when recording in the browser's performance panel; it only works in development builds.
solid answer
~40 sSetting `app.config.performance = true` before mounting makes Vue call `performance.mark()` and `performance.measure()` around the phases it already tracks for each component — `init`, `compile` (runtime template compilation), `render`, `patch`, `mount` and `hydrate`. Each measure is named like `<SearchResults> render`, so when you **record a trace in the browser's performance panel**, Vue's work appears in the timings track, aligned with scripting, layout and paint. Vue clears the marks and measures right after creating them, so reading `performance.getEntriesByType('measure')` later finds nothing; record a trace, or observe entries as they are created. It works **only in development mode** and in browsers with the `performance.mark` API; production builds contain no calls to it.
code
ts · 17 linesimport { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
if (import.meta.env.DEV) {
app.config.performance = true
// Vue clears its measures right after creating them, so observe them live
new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 8) console.log(entry.name, entry.duration.toFixed(1))
}
}).observe({ type: 'measure' })
}
app.mount('#app')go deeper
Recall that app.config.performance adds Vue component timings to the browser's performance recording in development builds.
Name the measured phases and explain that measures are named after components and appear as user timings in a recorded trace.
Use the measures to split a long task into Vue's render and patch versus other work, and know that they are cleared immediately.
Decide how development-only timing fits a team's performance process alongside production measurement, which Vue's option cannot provide.
## What the option is `app.config.performance` is a boolean on the application's config object. It defaults to off. Turning it on asks the runtime to publish its per-component timings through the browser's **User Timing API** — the standard `performance.mark()` / `performance.measure()` calls — so they show up in the browser's own profiling tools. ```ts import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) if (import.meta.env.DEV) { app.config.performance = true } app.mount('#app') ``` ## What gets measured The runtime wraps several phases of each component's life in a start/end pair. With the option on, each pair becomes: 1. A mark named `vue-<phase>-<uid>` at the start (the uid is the component instance's id). 2. A mark with `:end` appended at the end. 3. A measure named `<ComponentName> <phase>` spanning the two. 4. Immediately afterwards, the measure and both marks are cleared. The phases are: | Phase | Measured around | |---|---| | `init` | Setting up the instance, including `setup()` | | `compile` | Compiling a template in the browser (full build only) | | `render` | Running the render function | | `patch` | Applying the new vnode tree to the DOM | | `mount` | The complete first mount | | `hydrate` | Hydrating server-rendered markup | Because measures are named after the component, a trace shows `<ProductGrid> patch` directly, instead of an anonymous stack of runtime functions. ## Where you see it - **The browser's performance panel.** Start recording, perform the slow interaction, stop. The Vue measures appear in the timings (User Timing) track, lined up with the main-thread activity, so you can see whether a long task is mostly `<ProductGrid> patch` or something outside Vue. - **A `PerformanceObserver`** registered for `measure` entries receives them as they are created, which suits automated checks in development. - **Not** in `performance.getEntriesByType('measure')` after the fact: Vue clears each measure right after creating it, so the buffer is empty by the time you look. ## Limits to know - **Development only.** Every call that starts or ends a measurement in the renderer sits behind a development-mode guard, so a production bundle produces no marks whatever the option says. - **Browser support.** The runtime checks that `window.performance` exists; in environments without it, the option does nothing. - **Overhead.** Marks and measures cost time. Development builds are already slower than production; treat the numbers as relative. - **Scope.** It measures Vue's own phases. Time spent in your event handlers, fetches or third-party code shows up in the trace, but not under a Vue measure. ## How it relates to the other tools - The **Vue devtools** receive the same phase boundaries and show them per component in their own UI. - `app.config.performance` puts them in the **browser's** timeline instead, which matters when the question is how Vue's work interleaves with layout, paint and other scripts. - Neither tells you **why** a component rendered; for that, the `onRenderTriggered` debug hook reports the reactive change that triggered it. ## Reading the measures in a trace - Measures **nest**. When a parent patch updates a child whose props changed, the child's `render` and `patch` run inside the parent's `patch`, so the child's measures sit under the parent's in the timings track. - A component that re-renders because of **its own** state change gets its own top-level `render`/`patch` pair, separate from its parent. - Many short measures for the same component name in one interaction usually mean many instances — a list — rather than one slow component. - A long `patch` with a short `render` points at DOM work; a long `render` points at template or computed work. - Gaps between Vue measures inside one long task are your own code or the browser: handlers, watchers, layout. The practical sequence is: record, find the long task, read which Vue measures fill it, and only then decide whether the fix belongs in Vue components at all. ## Common mistakes - Enabling it and then looking for output in the console — it writes nothing there. - Enabling it on a production build and concluding Vue is "free" because no measures appear. - Setting it after `mount()` and missing the timings of the first mount.
- Why does `performance.getEntriesByType('measure')` return nothing from Vue even with `app.config.performance` on?After creating each measure, Vue calls `clearMeasures` and `clearMarks` for it, so the performance buffer never keeps them. A recording in the performance panel or a `PerformanceObserver` registered before the work captures them as they are created.
- A trace shows a 120 ms long task during a click, and inside it a 90 ms `<DataTable> patch` measure. What does that tell you?Most of the task is the renderer applying `DataTable`'s changes to the DOM, not your handler or the render function. The next question is why so much DOM changes on that click — too many rows updated, or rows replaced instead of patched — before reaching for a fix.
saying these in an interview costs you the question
- Expects app.config.performance output to appear in the console.
- Believes it produces marks in production builds too.
- Thinks the measures can be read later with getEntriesByType.
- Says it explains why a component re-rendered, not just how long it took.
- Enables it after mount and expects first-mount timings.