Since its inception, Vue has relied on a Virtual DOM to manage UI updates. It works, and it works well, but it comes at a cost: more JavaScript to parse, more memory to maintain that virtual representation, and more work on every update cycle.
Vue 3.6 introduces Vapor Mode, an alternative compilation strategy that removes the Virtual DOM entirely. Vapor components generate direct DOM manipulations, similar to what SolidJS does.
How to enable it
Add the vapor attribute to <script setup>:
<script setup vapor>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">{{ count }}</button>
</template>
Your code stays the same. Templates and the Composition API work exactly as before. What changes is what the compiler produces under the hood: instead of Virtual DOM render functions, it outputs code that creates and updates real DOM nodes directly.
Full app vs. mixed mode
If all your components use Vapor, you can create the app with createVaporApp and drop the Virtual DOM runtime from the bundle entirely:
import { createVaporApp } from 'vue'
import App from './App.vue'
createVaporApp(App).mount('#app')
But it's not all-or-nothing. If you have an existing app with VDOM components and want to migrate gradually, you can mix both modes with vaporInteropPlugin:
import { createApp, vaporInteropPlugin } from 'vue'
import App from './App.vue'
createApp(App)
.use(vaporInteropPlugin)
.mount('#app')
This way you can convert individual components to Vapor without touching the rest.
What doesn't work (yet)
Vapor Mode has some limitations you should know about:
- Composition API only: the Options API is not supported. If you're still using
data(),methodsand friends, you'll need to migrate first. <script setup>only: it doesn't work with the manualsetup()function.getCurrentInstance()returnsnull.app.config.globalPropertiesis not available.- Per-element lifecycle events (
@vue:mounted, etc.) don't work.
The numbers
In official benchmarks, Vue 3.6 with Vapor Mode mounts 100,000 components in ~100ms, placing it on par with SolidJS. The base bundle weighs under 10KB.
Conclusion
Vapor Mode is arguably the most significant change in Vue since the Composition API. It doesn't force you to rewrite anything — just add one word (vapor) and let the compiler do the heavy lifting. Vue 3.6 is in beta, but Vapor's feature set is complete for all stable APIs.
