Vue 3 Compiler PatchFlags: TEXT, CLASS, PROPS VNode Optimization
- Last updated
- Prerequisites:
- Virtual DOM diffing algorithms
- Bitwise operators in JavaScript
- vue
- compiler
- patchflags
- virtual-dom
- optimization
- vnode
Read at your depth
The practical view
PatchFlags are numeric bitwise hints generated by the Vue 3 template compiler. When an element has dynamic text (`<h1>{{ title }}</h1>`), the compiler emits `/* TEXT */ 1`. When an element has dynamic classes (`:class="cls"`), it emits `/* CLASS */ 2`. When the Virtual DOM diff runs, Vue uses fast bitwise operations (`patchFlag & PatchFlags.TEXT`) to diff *only* the specific dynamic attribute, completely skipping static props and children.
The same idea in other frameworks
Standard recursive Fiber reconciliation (no compiler-generated bitwise patch flags).Ivy compiler instruction flags (e.g. `ɵɵtextInterpolate1`).Bitwise `PatchFlags` (`TEXT`, `CLASS`, `PROPS`) in compiled `createVNode` calls.Compile-time direct DOM update blocks (zero VNode diffing).Legacy vs modern
Unoptimized Full VNode Diff vs Compiler PatchFlag Optimization
Unoptimized VNodes require iterating all props on every update; PatchFlags restrict diffing to exact bitwise targets.
createVNode('div', { id: 'fixed', class: dynamicClass }, text); // ❌ Diffs all props_createVNode("div", { class: _normalizeClass(cls) }, _toDisplayString(msg), 3 /* TEXT, CLASS */); // ✅ Fast bitwise checkInterview gotchas
Context
Interviewers test your knowledge of compiler optimization boundaries and bailouts.
The mechanical answer
`PatchFlags.BAIL = -1` instructs the runtime to **bail out of optimized diffing** and fall back to full, unoptimized recursive tree diffing. This occurs when a template uses features that prevent static analysis (such as custom render functions, dynamic slots without static keys, or manual VNode injections).
Trap
Render functions written manually with `h()` default to full diffing unless you explicitly pass patch flag constants.
Context
Checks precision regarding dynamic attribute optimization.
The mechanical answer
When an element has dynamic attributes other than `class` or `style` (e.g. `:id="id" :title="title"`), the compiler sets `PatchFlags.PROPS` (8) and attaches an array of string keys `dynamicProps: ['id', 'title']`. The runtime loops *only* through the keys listed in `dynamicProps`, ignoring all other static attributes.
Trap
If an element has `v-bind="object"` (dynamic object spread), Vue must use `FULL_PROPS = 16` because the keys themselves can change dynamically.