Vue 3.6 Vapor Mode: Components Without the Virtual DOM

Vapor Mode in Vue 3.6 lets you build components that manipulate the DOM directly, skipping the Virtual DOM entirely. Less JavaScript, less memory, better performance.


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>:

Vue
Counter.vue
<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:

JS
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:

JS
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(), methods and friends, you'll need to migrate first.
  • <script setup> only: it doesn't work with the manual setup() function.
  • getCurrentInstance() returns null.
  • app.config.globalProperties is 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.

Documentation

Juan Andrés Núñez
Juan Andrés Núñez
Senior Frontend Engineer. Vue.js specialist. Speaker. Professional teacher. Stoic.