[{"data":1,"prerenderedAt":1177},["ShallowReactive",2],{"en-article-\u002Fen\u002Fblog\u002Fvue-vapor-mode-what-it-is-and-how-to-use-it":3,"en-related-posts-\u002Fen\u002Fblog\u002Fvue-vapor-mode-what-it-is-and-how-to-use-it":1072},{"id":4,"title":5,"articleCover":6,"articleCoverEmbed":7,"articleCoverEmbedUploadDate":7,"articleCoverHeight":8,"articleCoverWidth":9,"authorId":10,"body":11,"categoriesIds":1057,"description":1060,"enAlternateSlug":1061,"extension":1062,"meta":1063,"navigation":175,"path":1064,"ptBrAlternateSlug":1065,"publishedAt":1066,"seo":1067,"sitemap":1068,"stem":1069,"updatedAt":1066,"wordCount":1070,"__hash__":1071},"blogEn\u002Fen\u002Fblog\u002Fvue-vapor-mode-what-it-is-and-how-to-use-it.md","Vue Vapor Mode: what it is and what changes in Vue 3.6","\u002Fimages\u002Fen\u002Fblog\u002Fvue\u002Fvue-vapor-mode-what-it-is-and-how-to-use-it.webp",null,720,1280,"thiago-nunes-batista",{"type":12,"value":13,"toc":1031},"minimark",[14,31,38,43,46,49,52,57,87,91,102,275,282,297,301,312,382,385,389,396,453,462,466,472,524,538,541,608,619,622,626,629,691,700,707,710,717,731,766,773,777,780,896,911,915,918,925,929,932,935,952,956,960,963,967,975,979,984,988,997,1001,1004,1008,1020,1024,1027],[15,16,17,18,22,23,26,27,30],"p",{},"Vue 3.6 is not stable yet. As of October 6, 2026, the latest version is ",[19,20,21],"code",{},"3.6.0-rc.10"," (September 30), and the stable release is still ",[19,24,25],{},"3.5.43"," (September 17). I checked both on npm and in the ",[19,28,29],{},"vuejs\u002Fcore"," releases on that date.",[15,32,33,37],{},[34,35,36],"strong",{},"Vue Vapor Mode"," is the headline feature of 3.6: a compilation mode that skips the Virtual DOM and generates code that updates the DOM directly. It is opt-in, so you pick which components use it and you don't rewrite your app. This article covers how Vapor works, how to enable it in Vue and in Nuxt 4.6, what it doesn't support yet, and when it's worth a try.",[39,40,42],"h2",{"id":41},"how-vapor-works","How Vapor works",[15,44,45],{},"In the traditional mode, when reactive state changes, Vue runs the render function, builds a new tree of VNodes (plain JavaScript objects that describe the UI), compares it with the previous tree, and only then touches the real DOM.",[15,47,48],{},"In Vapor Mode, the compiler analyzes the template and generates code that manipulates the DOM directly. Vapor components don't create VNodes or diff trees at runtime. When a reactive value changes, only the part of the DOM bound to it is updated.",[15,50,51],{},"According to the official Vue 3.6 release notes, the goal is a smaller baseline bundle and better performance. The same notes say Vapor reached the same level of performance as Solid and Svelte 5 in third-party benchmarks (js-framework-benchmark). As with any benchmark, the result depends on the scenario measured.",[53,54,56],"h3",{"id":55},"what-about-alien-signals","What about Alien Signals?",[15,58,59,60,63,64,71,72,75,76,75,79,82,83,86],{},"Vue 3.6 also ships a major refactor of ",[19,61,62],{},"@vue\u002Freactivity"," based on the ",[65,66,70],"a",{"href":67,"rel":68},"https:\u002F\u002Fgithub.com\u002Fstackblitz\u002Falien-signals",[69],"nofollow","alien-signals"," library. The rc.1 notes say it improves the reactivity system's performance and memory usage. It's an internal change: ",[19,73,74],{},"ref",", ",[19,77,78],{},"reactive",[19,80,81],{},"computed"," and ",[19,84,85],{},"watch"," keep the same API. Since it's part of Vue 3.6, you get it whether or not you use Vapor.",[39,88,90],{"id":89},"how-to-enable-vapor-mode","How to enable Vapor Mode",[15,92,93,94,97,98,101],{},"Vapor works with SFCs that use ",[19,95,96],{},"\u003Cscript setup>"," or only a template. You mark the component with the ",[19,99,100],{},"vapor"," attribute:",[103,104,109],"pre",{"className":105,"code":106,"language":107,"meta":108,"style":108},"language-vue shiki shiki-themes dracula","\u003Cscript setup vapor lang=\"ts\">\nimport { ref } from 'vue'\n\nconst count = ref(0)\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cbutton @click=\"count++\">\n    count is {{ count }}\n  \u003C\u002Fbutton>\n\u003C\u002Ftemplate>\n","vue","",[19,110,111,150,170,177,202,212,217,227,250,256,266],{"__ignoreMap":108},[112,113,116,120,124,128,131,134,137,141,145,147],"span",{"class":114,"line":115},"line",1,[112,117,119],{"class":118},"sCdxs","\u003C",[112,121,123],{"class":122},"s0Tla","script",[112,125,127],{"class":126},"sY_PY"," setup",[112,129,130],{"class":126}," vapor",[112,132,133],{"class":126}," lang",[112,135,136],{"class":122},"=",[112,138,140],{"class":139},"seVfx","\"",[112,142,144],{"class":143},"s-mGx","ts",[112,146,140],{"class":139},[112,148,149],{"class":118},">\n",[112,151,153,156,159,162,165,167],{"class":114,"line":152},2,[112,154,155],{"class":122},"import",[112,157,158],{"class":118}," { ref } ",[112,160,161],{"class":122},"from",[112,163,164],{"class":139}," '",[112,166,107],{"class":143},[112,168,169],{"class":139},"'\n",[112,171,173],{"class":114,"line":172},3,[112,174,176],{"emptyLinePlaceholder":175},true,"\n",[112,178,180,183,186,188,192,195,199],{"class":114,"line":179},4,[112,181,182],{"class":122},"const",[112,184,185],{"class":118}," count ",[112,187,136],{"class":122},[112,189,191],{"class":190},"sAOxA"," ref",[112,193,194],{"class":118},"(",[112,196,198],{"class":197},"sIQBb","0",[112,200,201],{"class":118},")\n",[112,203,205,208,210],{"class":114,"line":204},5,[112,206,207],{"class":118},"\u003C\u002F",[112,209,123],{"class":122},[112,211,149],{"class":118},[112,213,215],{"class":114,"line":214},6,[112,216,176],{"emptyLinePlaceholder":175},[112,218,220,222,225],{"class":114,"line":219},7,[112,221,119],{"class":118},[112,223,224],{"class":122},"template",[112,226,149],{"class":118},[112,228,230,233,236,239,241,243,246,248],{"class":114,"line":229},8,[112,231,232],{"class":118},"  \u003C",[112,234,235],{"class":122},"button",[112,237,238],{"class":126}," @click",[112,240,136],{"class":122},[112,242,140],{"class":139},[112,244,245],{"class":143},"count++",[112,247,140],{"class":139},[112,249,149],{"class":118},[112,251,253],{"class":114,"line":252},9,[112,254,255],{"class":118},"    count is {{ count }}\n",[112,257,259,262,264],{"class":114,"line":258},10,[112,260,261],{"class":118},"  \u003C\u002F",[112,263,235],{"class":122},[112,265,149],{"class":118},[112,267,269,271,273],{"class":114,"line":268},11,[112,270,207],{"class":118},[112,272,224],{"class":122},[112,274,149],{"class":118},[15,276,277,278,281],{},"Outside Nuxt, ",[19,279,280],{},"@vitejs\u002Fplugin-vue"," compiles Vapor SFCs (the plugin's changelog records Vapor component support, including template-only ones), so use a recent version.",[15,283,284,285,288,289,292,293,296],{},"Vue also accepts ",[19,286,287],{},"\u003Cscript vapor>"," as shorthand for ",[19,290,291],{},"\u003Cscript setup vapor>",". You can instead put the marker on the template with ",[19,294,295],{},"\u003Ctemplate vapor>"," to compile the whole SFC in Vapor mode.",[53,298,300],{"id":299},"vapor-components-in-an-existing-app","Vapor components in an existing app",[15,302,303,304,307,308,311],{},"In an app created with ",[19,305,306],{},"createApp()",", you need to install ",[19,309,310],{},"vaporInteropPlugin"," to use Vapor components:",[103,313,316],{"className":314,"code":315,"language":144,"meta":108,"style":108},"language-ts shiki shiki-themes dracula","import { createApp, vaporInteropPlugin } from 'vue'\nimport App from '.\u002FApp.vue'\n\ncreateApp(App).use(vaporInteropPlugin).mount('#app')\n",[19,317,318,333,349,353],{"__ignoreMap":108},[112,319,320,322,325,327,329,331],{"class":114,"line":115},[112,321,155],{"class":122},[112,323,324],{"class":118}," { createApp, vaporInteropPlugin } ",[112,326,161],{"class":122},[112,328,164],{"class":139},[112,330,107],{"class":143},[112,332,169],{"class":139},[112,334,335,337,340,342,344,347],{"class":114,"line":152},[112,336,155],{"class":122},[112,338,339],{"class":118}," App ",[112,341,161],{"class":122},[112,343,164],{"class":139},[112,345,346],{"class":143},".\u002FApp.vue",[112,348,169],{"class":139},[112,350,351],{"class":114,"line":172},[112,352,176],{"emptyLinePlaceholder":175},[112,354,355,358,361,364,367,370,372,375,378,380],{"class":114,"line":179},[112,356,357],{"class":190},"createApp",[112,359,360],{"class":118},"(App).",[112,362,363],{"class":190},"use",[112,365,366],{"class":118},"(vaporInteropPlugin).",[112,368,369],{"class":190},"mount",[112,371,194],{"class":118},[112,373,374],{"class":139},"'",[112,376,377],{"class":143},"#app",[112,379,374],{"class":139},[112,381,201],{"class":118},[15,383,384],{},"With the plugin installed, Vapor and regular components can be nested inside each other. The Vue notes warn that this covers props, events and slots in standard usage, but not every edge case yet. Their advice is to keep distinct regions in the app, each in one mode, and to avoid mixed nesting where you can.",[53,386,388],{"id":387},"a-fully-vapor-app","A fully Vapor app",[15,390,391,392,395],{},"If every component is Vapor, use ",[19,393,394],{},"createVaporApp()",":",[103,397,399],{"className":314,"code":398,"language":144,"meta":108,"style":108},"import { createVaporApp } from 'vue'\nimport App from '.\u002FApp.vue'\n\ncreateVaporApp(App).mount('#app')\n",[19,400,401,416,430,434],{"__ignoreMap":108},[112,402,403,405,408,410,412,414],{"class":114,"line":115},[112,404,155],{"class":122},[112,406,407],{"class":118}," { createVaporApp } ",[112,409,161],{"class":122},[112,411,164],{"class":139},[112,413,107],{"class":143},[112,415,169],{"class":139},[112,417,418,420,422,424,426,428],{"class":114,"line":152},[112,419,155],{"class":122},[112,421,339],{"class":118},[112,423,161],{"class":122},[112,425,164],{"class":139},[112,427,346],{"class":143},[112,429,169],{"class":139},[112,431,432],{"class":114,"line":172},[112,433,176],{"emptyLinePlaceholder":175},[112,435,436,439,441,443,445,447,449,451],{"class":114,"line":179},[112,437,438],{"class":190},"createVaporApp",[112,440,360],{"class":118},[112,442,369],{"class":190},[112,444,194],{"class":118},[112,446,374],{"class":139},[112,448,377],{"class":143},[112,450,374],{"class":139},[112,452,201],{"class":118},[15,454,455,456,458,459,461],{},"The Virtual DOM runtime then stays out of the bundle. Each component still needs the ",[19,457,100],{}," marker. Components written with render functions or JSX remain Virtual DOM components and need interop. A Vapor app can also install ",[19,460,310],{}," to accept Virtual DOM components, but that pulls the runtime back in and cuts into the bundle savings.",[39,463,465],{"id":464},"vapor-in-nuxt-46","Vapor in Nuxt 4.6",[15,467,468,469,395],{},"Nuxt 4.6, released on October 5, 2026, supports Vapor in interop mode. The app root stays on the Virtual DOM, and you choose which components or pages use Vapor. To enable it, turn the option on in ",[19,470,471],{},"nuxt.config.ts",[103,473,475],{"className":314,"code":474,"language":144,"meta":108,"style":108},"export default defineNuxtConfig({\n  vue: {\n    vapor: true,\n  },\n})\n",[19,476,477,491,501,514,519],{"__ignoreMap":108},[112,478,479,482,485,488],{"class":114,"line":115},[112,480,481],{"class":122},"export",[112,483,484],{"class":122}," default",[112,486,487],{"class":190}," defineNuxtConfig",[112,489,490],{"class":118},"({\n",[112,492,493,496,498],{"class":114,"line":152},[112,494,495],{"class":118},"  vue",[112,497,395],{"class":122},[112,499,500],{"class":118}," {\n",[112,502,503,506,508,511],{"class":114,"line":172},[112,504,505],{"class":118},"    vapor",[112,507,395],{"class":122},[112,509,510],{"class":197}," true",[112,512,513],{"class":118},",\n",[112,515,516],{"class":114,"line":179},[112,517,518],{"class":118},"  },\n",[112,520,521],{"class":114,"line":204},[112,522,523],{"class":118},"})\n",[15,525,526,527,529,530,533,534,537],{},"Then mark components with ",[19,528,291],{},", as in the example above. Nuxt requires Vue ",[19,531,532],{},"^3.6.0-rc.2"," or newer. According to the release post, routing, ",[19,535,536],{},"useAsyncData",", layouts and most built-in components keep working unchanged. The post recommends trying Vapor in a fresh project first.",[15,539,540],{},"The Nuxt docs list a few limitations of interop mode:",[542,543,544,548,555,575,582,601],"ul",{},[545,546,547],"li",{},"the app root can't be Vapor, because fully Vapor apps aren't available in Nuxt;",[545,549,550,551,554],{},"Vapor components don't expose ",[19,552,553],{},"$el"," on template refs;",[545,556,557,560,561,564,565,75,568,82,571,574],{},[19,558,559],{},"\u003CClientOnly>"," skips its attribute forwarding, and ",[19,562,563],{},"\u003CNuxtIsland>",", server components and the head components that read text children (",[19,566,567],{},"\u003CTitle>",[19,569,570],{},"\u003CStyle>",[19,572,573],{},"\u003CNoscript>",") warn if you pass them a Vapor slot;",[545,576,577,578,581],{},"keyed ",[19,579,580],{},"onPrehydrate"," falls back to the unkeyed form (and warns in development), because there is no component instance to attach the key to;",[545,583,584,82,587,590,591,594,595,597,598,600],{},[19,585,586],{},"asyncData",[19,588,589],{},"fetchKey"," through ",[19,592,593],{},"defineNuxtComponent"," don't work (use ",[19,596,536],{}," in ",[19,599,96],{},");",[545,602,603,604,607],{},"Nuxt composables called after an ",[19,605,606],{},"await"," may lose their context.",[15,609,610,611,614,615,618],{},"The same release post has performance numbers for Nuxt 4.6: ",[19,612,613],{},"nuxt build"," on a starter project went from 4.4 s to 3.6 s (18% faster), and a page with 300 ",[19,616,617],{},"\u003CNuxtLink>","s went from 110 to 140 req\u002Fs in SSR (+26%). Nuxt credits those gains to general optimizations in the release, not to Vapor.",[15,620,621],{},"If you're still on Nuxt 3, it reached end of life on July 31, 2026.",[39,623,625],{"id":624},"what-vapor-doesnt-support-yet","What Vapor doesn't support yet",[15,627,628],{},"Vapor supports a subset of Vue's APIs. The official notes list what is unavailable or doesn't apply in Vapor components:",[542,630,631,649,654,663,669,674],{},[545,632,633,634,75,637,75,640,643,644,648],{},"the Options API (",[19,635,636],{},"data",[19,638,639],{},"methods",[19,641,642],{},"mounted"," and so on). If you want a refresher on the difference, see ",[65,645,647],{"href":646},"\u002Fen\u002Fblog\u002Fwhat-is-the-difference-between-composition-api-and-options-api-in-vuejs","Composition API vs Options API",";",[545,650,651,648],{},[19,652,653],{},"app.config.globalProperties",[545,655,656,659,660,648],{},[19,657,658],{},"getCurrentInstance()",", which returns ",[19,661,662],{},"null",[545,664,665,666,648],{},"per-element lifecycle events such as ",[19,667,668],{},"@vue:mounted",[545,670,671,648],{},[19,672,673],{},"v-memo",[545,675,676,75,678,75,681,75,684,82,687,690],{},[19,677,553],{},[19,679,680],{},"$props",[19,682,683],{},"$attrs",[19,685,686],{},"$slots",[19,688,689],{},"$refs"," on component template refs.",[15,692,693,694,696,697,699],{},"Component libraries built on the Virtual DOM also deserve testing. The notes mention \"rough edges\" when using a Virtual DOM component library inside Vapor, without naming any library. If one of them relies on ",[19,695,658],{},", the ",[19,698,662],{}," above could be a problem, but only a test in your own project will tell.",[15,701,702,703,706],{},"The official notes don't list ",[19,704,705],{},"\u003CSuspense>"," or Vue DevTools as incompatible with Vapor, but that doesn't guarantee full support. The RC changelog records several fixes for Vapor and Suspense integration, so support is still being worked on. Test both in your own setup before deciding.",[15,708,709],{},"The same goes for SSR. The RC changelog has several hydration fixes for Vapor components, which suggests SSR is supported but still being tuned. If your app renders on the server, test hydration carefully.",[53,711,713,714],{"id":712},"events-and-delegate","Events and ",[19,715,716],{},".delegate",[15,718,719,720,723,724,727,728,730],{},"In earlier RCs, Vapor delegated events to ",[19,721,722],{},"document",", so a ",[19,725,726],{},"stopPropagation()"," on an ancestor could stop a child's handler. Since rc.2, listeners are attached directly to the element, as in regular Vue, and delegation became opt-in through the ",[19,729,716],{}," modifier:",[103,732,734],{"className":105,"code":733,"language":107,"meta":108,"style":108},"\u003Cbutton @click.delegate=\"onClick\" \u002F>\n",[19,735,736],{"__ignoreMap":108},[112,737,738,740,742,745,748,751,754,756,758,761,763],{"class":114,"line":115},[112,739,119],{"class":118},[112,741,235],{"class":122},[112,743,744],{"class":118}," @",[112,746,747],{"class":126},"click",[112,749,750],{"class":118},".",[112,752,753],{"class":126},"delegate",[112,755,136],{"class":122},[112,757,140],{"class":139},[112,759,760],{"class":118},"onClick",[112,762,140],{"class":139},[112,764,765],{"class":118}," \u002F>\n",[15,767,768,769,772],{},"The ",[19,770,771],{},"compilerOptions.eventDelegation"," option was removed.",[53,774,776],{"id":775},"custom-directives","Custom directives",[15,778,779],{},"Custom directives also have a different interface in Vapor. Instead of an object with hooks, you write a function that receives the element and a reactive getter, and it can return a cleanup function:",[103,781,783],{"className":314,"code":782,"language":144,"meta":108,"style":108},"import { watchEffect } from 'vue'\n\nconst MyDirective = (el, source) => {\n  watchEffect(() => {\n    el.textContent = source()\n  })\n  return () => console.log('cleanup')\n}\n",[19,784,785,800,804,834,846,859,864,891],{"__ignoreMap":108},[112,786,787,789,792,794,796,798],{"class":114,"line":115},[112,788,155],{"class":122},[112,790,791],{"class":118}," { watchEffect } ",[112,793,161],{"class":122},[112,795,164],{"class":139},[112,797,107],{"class":143},[112,799,169],{"class":139},[112,801,802],{"class":114,"line":152},[112,803,176],{"emptyLinePlaceholder":175},[112,805,806,808,811,814,817,821,823,826,829,832],{"class":114,"line":172},[112,807,182],{"class":122},[112,809,810],{"class":190}," MyDirective",[112,812,813],{"class":122}," =",[112,815,816],{"class":118}," (",[112,818,820],{"class":819},"sGEwX","el",[112,822,75],{"class":118},[112,824,825],{"class":819},"source",[112,827,828],{"class":118},") ",[112,830,831],{"class":122},"=>",[112,833,500],{"class":118},[112,835,836,839,842,844],{"class":114,"line":179},[112,837,838],{"class":190},"  watchEffect",[112,840,841],{"class":118},"(() ",[112,843,831],{"class":122},[112,845,500],{"class":118},[112,847,848,851,853,856],{"class":114,"line":204},[112,849,850],{"class":118},"    el.textContent ",[112,852,136],{"class":122},[112,854,855],{"class":190}," source",[112,857,858],{"class":118},"()\n",[112,860,861],{"class":114,"line":214},[112,862,863],{"class":118},"  })\n",[112,865,866,869,872,874,877,880,882,884,887,889],{"class":114,"line":219},[112,867,868],{"class":122},"  return",[112,870,871],{"class":118}," () ",[112,873,831],{"class":122},[112,875,876],{"class":118}," console.",[112,878,879],{"class":190},"log",[112,881,194],{"class":118},[112,883,374],{"class":139},[112,885,886],{"class":143},"cleanup",[112,888,374],{"class":139},[112,890,201],{"class":118},[112,892,893],{"class":114,"line":229},[112,894,895],{"class":118},"}\n",[15,897,898,899,902,903,906,907,750],{},"The full signature is ",[19,900,901],{},"(node, value?, argument?, modifiers?)",", where ",[19,904,905],{},"value"," is the reactive getter. For a refresher on the traditional model, see ",[65,908,910],{"href":909},"\u002Fen\u002Fblog\u002Fwhat-are-directives-in-vue-and-how-to-implement-them","what directives are in Vue",[39,912,914],{"id":913},"where-vapor-helps","Where Vapor helps",[15,916,917],{},"The gain shows up where an app does a lot of DOM update work: dense lists and tables, components that change several times per second, and pages where initial JavaScript size matters. For an ordinary CRUD app, users will likely not notice the difference.",[15,919,920,921,924],{},"Vapor also doesn't fix problems that don't come from the renderer. Rendering 10,000 items in the DOM is slow in both modes, and the fix is to virtualize the list. Calling heavy functions straight from the template, like ",[19,922,923],{},"{{ calculateTotal(item) }}",", is still a bad idea in both modes.",[39,926,928],{"id":927},"should-you-adopt-it-now","Should you adopt it now?",[15,930,931],{},"The Vue team says Vapor's feature set is complete in the RC and recommends two uses for now: applying Vapor to parts of an existing app, such as a performance-sensitive page, and building small new apps entirely in Vapor.",[15,933,934],{},"For a production app that already runs well on Vue 3.5, waiting for the stable release is the safer choice. For an isolated page where you've already measured a bottleneck, a trial in Nuxt 4.6 or in a Vue app with interop is a reasonable experiment. Before you start, check that:",[542,936,937,940,946,949],{},[545,938,939],{},"you measured current performance (the browser's Performance panel works) and found a rendering bottleneck;",[545,941,942,943,945],{},"the component uses ",[19,944,96],{}," or only a template;",[545,947,948],{},"the UI libraries it relies on work with interop in your project;",[545,950,951],{},"you can isolate Vapor to one route or component and back it out without pain.",[39,953,955],{"id":954},"frequently-asked-questions","Frequently asked questions",[53,957,959],{"id":958},"what-is-vapor-mode-in-vue","What is Vapor Mode in Vue?",[15,961,962],{},"It's an opt-in compilation mode for SFCs, available in the Vue 3.6 RC. Instead of building and diffing a Virtual DOM tree at runtime, the compiler generates code that updates the DOM directly.",[53,964,966],{"id":965},"is-vue-36-stable-yet","Is Vue 3.6 stable yet?",[15,968,969,970,972,973,750],{},"Not yet. As of October 6, 2026, the latest version is ",[19,971,21],{}," and the stable release is ",[19,974,25],{},[53,976,978],{"id":977},"does-vapor-mode-replace-the-virtual-dom","Does Vapor Mode replace the Virtual DOM?",[15,980,981,982,750],{},"No. It's optional and lives alongside the Virtual DOM in the same app through ",[19,983,310],{},[53,985,987],{"id":986},"do-i-need-to-rewrite-my-app-to-use-vapor","Do I need to rewrite my app to use Vapor?",[15,989,990,991,993,994,996],{},"No. You can mark one component at a time with ",[19,992,100],{},". Components that use the Options API stay out, because Vapor only accepts ",[19,995,96],{}," and templates.",[53,998,1000],{"id":999},"does-vapor-mode-work-with-the-options-api","Does Vapor Mode work with the Options API?",[15,1002,1003],{},"No. The official notes list the Options API as unsupported.",[53,1005,1007],{"id":1006},"does-vapor-mode-work-with-nuxt","Does Vapor Mode work with Nuxt?",[15,1009,1010,1011,597,1014,1016,1017,1019],{},"Yes, since Nuxt 4.6, in interop mode: set ",[19,1012,1013],{},"vue: { vapor: true }",[19,1015,471],{}," and mark components with ",[19,1018,291],{},". The app root stays on the Virtual DOM.",[53,1021,1023],{"id":1022},"is-vapor-mode-faster-than-the-virtual-dom","Is Vapor Mode faster than the Virtual DOM?",[15,1025,1026],{},"According to the Vue 3.6 notes, Vapor reached Solid and Svelte 5 levels in third-party benchmarks. For most apps the perceived gain is small, and the real effect on your project only shows up when you measure it.",[1028,1029,1030],"style",{},"html pre.shiki code .sCdxs, html code.shiki .sCdxs{--shiki-default:#F8F8F2}html pre.shiki code .s0Tla, html code.shiki .s0Tla{--shiki-default:#FF79C6}html pre.shiki code .sY_PY, html code.shiki .sY_PY{--shiki-default:#50FA7B;--shiki-default-font-style:italic}html pre.shiki code .seVfx, html code.shiki .seVfx{--shiki-default:#E9F284}html pre.shiki code .s-mGx, html code.shiki .s-mGx{--shiki-default:#F1FA8C}html pre.shiki code .sAOxA, html code.shiki .sAOxA{--shiki-default:#50FA7B}html pre.shiki code .sIQBb, html code.shiki .sIQBb{--shiki-default:#BD93F9}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sGEwX, html code.shiki .sGEwX{--shiki-default:#FFB86C;--shiki-default-font-style:italic}",{"title":108,"searchDepth":152,"depth":152,"links":1032},[1033,1036,1040,1041,1046,1047,1048],{"id":41,"depth":152,"text":42,"children":1034},[1035],{"id":55,"depth":172,"text":56},{"id":89,"depth":152,"text":90,"children":1037},[1038,1039],{"id":299,"depth":172,"text":300},{"id":387,"depth":172,"text":388},{"id":464,"depth":152,"text":465},{"id":624,"depth":152,"text":625,"children":1042},[1043,1045],{"id":712,"depth":172,"text":1044},"Events and .delegate",{"id":775,"depth":172,"text":776},{"id":913,"depth":152,"text":914},{"id":927,"depth":152,"text":928},{"id":954,"depth":152,"text":955,"children":1049},[1050,1051,1052,1053,1054,1055,1056],{"id":958,"depth":172,"text":959},{"id":965,"depth":172,"text":966},{"id":977,"depth":172,"text":978},{"id":986,"depth":172,"text":987},{"id":999,"depth":172,"text":1000},{"id":1006,"depth":172,"text":1007},{"id":1022,"depth":172,"text":1023},[1058,1059],"vuejs","nuxt","What Vue Vapor Mode is, how to turn it on in Vue 3.6 (RC) and Nuxt 4.6, what it doesn't support yet, and when it's worth trying, with code examples and an FAQ.","vue-vapor-mode-what-it-is-and-how-to-use-it","md",{},"\u002Fen\u002Fblog\u002Fvue-vapor-mode-what-it-is-and-how-to-use-it","vue-vapor-mode-como-funciona-e-como-usar","2026-10-06",{"title":5,"description":1060},{"loc":1064,"lastmod":1066},"en\u002Fblog\u002Fvue-vapor-mode-what-it-is-and-how-to-use-it",1612,"t7xqEIHrQ1NF0PTd4QIeo_dO6I9PgndCWb5gfcF3uhE",[1073,1082,1090,1097,1104,1112,1119,1127,1134,1142,1148,1156,1163,1165,1171],{"id":1074,"path":1075,"title":1076,"articleCover":1077,"categoriesIds":1078,"publishedAt":1081},"blogEn\u002Fen\u002Fblog\u002Fcore-web-vitals-how-user-experience-affects-seo.md","\u002Fen\u002Fblog\u002Fcore-web-vitals-how-user-experience-affects-seo","Core Web Vitals and SEO: How User Experience Affects Your Site","\u002Fimages\u002Fen\u002Fblog\u002Fseo\u002Fweb-vitals\u002Fcore-web-vitals-how-user-experience-affects-seo.webp",[1079,1080],"seo","web-vitals","2024-10-25",{"id":1083,"path":1084,"title":1085,"articleCover":1086,"categoriesIds":1087,"publishedAt":1089},"blogEn\u002Fen\u002Fblog\u002Ffree-developer-tools-hub.md","\u002Fen\u002Fblog\u002Ffree-developer-tools-hub","I Built a Free Web Tools Hub for Developers","\u002Fimages\u002Fen\u002Fblog\u002Ftools\u002Ffree-developer-tools-hub.webp",[1088],"tools","2026-01-06",{"id":1091,"path":1092,"title":1093,"articleCover":1094,"categoriesIds":1095,"publishedAt":1096},"blogEn\u002Fen\u002Fblog\u002Fhow-the-routing-system-works-in-nuxt.md","\u002Fen\u002Fblog\u002Fhow-the-routing-system-works-in-nuxt","Nuxt Routing: Dynamic, Nested and Catch-All Routes","\u002Fimages\u002Fblog\u002Fnuxt\u002Fnuxt-routing-thumb.webp",[1059,1058],"2025-03-12",{"id":1098,"path":1099,"title":1100,"articleCover":1101,"categoriesIds":1102,"publishedAt":1103},"blogEn\u002Fen\u002Fblog\u002Fhow-to-add-special-characters-on-i18n.md","\u002Fen\u002Fblog\u002Fhow-to-add-special-characters-on-i18n","How to Add Special Characters in i18N Translations","\u002Fimages\u002Fblog\u002Fi18n\u002Fi18n-special-characters-on-nuxtjs-thumb.webp",[1059,1058],"2025-02-02",{"id":1105,"path":1106,"title":1107,"articleCover":1108,"categoriesIds":1109,"publishedAt":1111},"blogEn\u002Fen\u002Fblog\u002Fhow-to-create-and-set-up-ssh-key-github.md","\u002Fen\u002Fblog\u002Fhow-to-create-and-set-up-ssh-key-github","SSH Key in Git: How to Set Up an SSH Key for GitHub","\u002Fimages\u002Fen\u002Fblog\u002Fgit\u002Fhow-to-create-and-set-up-ssh-key-github-thumb.webp",[1110],"git","2025-02-04",{"id":1113,"path":1114,"title":1115,"articleCover":1116,"categoriesIds":1117,"publishedAt":1118},"blogEn\u002Fen\u002Fblog\u002Fhow-to-create-structured-data-with-nuxtjs.md","\u002Fen\u002Fblog\u002Fhow-to-create-structured-data-with-nuxtjs","What is Structured Data and How to Add it in Nuxt.JS","\u002Fimages\u002Fen\u002Fblog\u002Fseo\u002Fstructured-data\u002Fstructured-data-thumb-1.webp",[1059,1058,1079],"2025-01-22",{"id":1120,"path":1121,"title":1122,"articleCover":1123,"categoriesIds":1124,"publishedAt":1126},"blogEn\u002Fen\u002Fblog\u002Fhow-to-deal-with-envy-from-other-programmers.md","\u002Fen\u002Fblog\u002Fhow-to-deal-with-envy-from-other-programmers","How to Deal with Envy from Other Programmers in Your Career","\u002Fimages\u002Fen\u002Fblog\u002Fcareer\u002Fa-nail-that-stands-out-gets-hammered.webp",[1125],"career","2025-08-29",{"id":1128,"path":1129,"title":1130,"articleCover":1131,"categoriesIds":1132,"publishedAt":1133},"blogEn\u002Fen\u002Fblog\u002Fhow-to-use-middlewares-nuxtjs.md","\u002Fen\u002Fblog\u002Fhow-to-use-middlewares-nuxtjs","Middlewares: What They Are and How to Use Them in Nuxt.JS","\u002Fimages\u002Fblog\u002Fnuxt\u002Ffront-end-middlewares-thumb.webp",[1059,1058],"2025-02-03",{"id":1135,"path":1136,"title":1137,"articleCover":1138,"categoriesIds":1139,"publishedAt":1141},"blogEn\u002Fen\u002Fblog\u002Fhow-to-validate-cpf-with-javascript.md","\u002Fen\u002Fblog\u002Fhow-to-validate-cpf-with-javascript","How to validate a CPF with JavaScript","\u002Fimages\u002Fen\u002Fblog\u002Fjavascript\u002Fhow-to-validate-cpf-with-javascript.webp",[1140,1088],"javascript","2026-10-04",{"id":1143,"path":1144,"title":1145,"articleCover":1146,"categoriesIds":1147,"publishedAt":1141},"blogEn\u002Fen\u002Fblog\u002Fhow-to-validate-credit-card-with-javascript.md","\u002Fen\u002Fblog\u002Fhow-to-validate-credit-card-with-javascript","How to validate a credit card with JavaScript (Luhn algorithm)","\u002Fimages\u002Fen\u002Fblog\u002Fjavascript\u002Fhow-to-validate-credit-card-with-javascript.webp",[1140,1088],{"id":1149,"path":1150,"title":1151,"articleCover":1152,"categoriesIds":1153,"publishedAt":1155},"blogEn\u002Fen\u002Fblog\u002Frecovering-lost-files-in-git-with-vscode.md","\u002Fen\u002Fblog\u002Frecovering-lost-files-in-git-with-vscode","Recover Lost Files in Git Without a Commit Using VS Code Local History","\u002Fimages\u002Fen\u002Fblog\u002Fvscode\u002Fhow-to-recover-lost-files-in-git-using-vscode.webp",[1110,1154],"vscode","2025-01-21",{"id":1157,"path":1158,"title":1159,"articleCover":1160,"categoriesIds":1161,"publishedAt":1162},"blogEn\u002Fen\u002Fblog\u002Fvercel-buys-nuxt-labs.md","\u002Fen\u002Fblog\u002Fvercel-buys-nuxt-labs","Vercel Acquired Nuxt Labs! What Does This Mean for Nuxt?","\u002Fimages\u002Fen\u002Fblog\u002Fnuxt\u002Fvercel-buys-nuxt-labs.webp",[1059],"2025-07-17",{"id":4,"path":1064,"title":5,"articleCover":6,"categoriesIds":1164,"publishedAt":1066},[1058,1059],{"id":1166,"path":909,"title":1167,"articleCover":1168,"categoriesIds":1169,"publishedAt":1170},"blogEn\u002Fen\u002Fblog\u002Fwhat-are-directives-in-vue-and-how-to-implement-them.md","Vue 3 Directives: Built-in and Custom","\u002Fimages\u002Fen\u002Fblog\u002Fvue\u002Fwhat-are-directives-in-vue-and-how-to-implement-them.webp",[1058],"2025-03-21",{"id":1172,"path":646,"title":1173,"articleCover":1174,"categoriesIds":1175,"publishedAt":1176},"blogEn\u002Fen\u002Fblog\u002Fwhat-is-the-difference-between-composition-api-and-options-api-in-vuejs.md","Composition API vs Options API in Vue.js: What's the Difference?","\u002Fimages\u002Fen\u002Fblog\u002Fvue\u002Fwhat-is-the-difference-between-composition-api-and-options-api-in-vuejs.webp",[1058],"2025-02-20",1791321320162]