Migrating from vue-meta to Unhead

Step-by-step guide to migrate your Vue app from vue-meta to Unhead for Vue 3 compatibility and modern head management.
Harlan WiltonHarlan Wilton6 mins read Published
What you'll learn
  • vue-meta never shipped Vue 3 support and was archived in 2025
  • Unhead is the modern replacement with full Vue 3 support
  • Most APIs translate directly—metaInfo becomes useHead/useSeoMeta

vue-meta was the standard for Vue 2 head management but never shipped a stable Vue 3 version. The repository was archived in October 2025 after years without updates. Unhead is its modern replacement—built by the same ecosystem, actively maintained, and Vue 3 native.

Quick Comparison

// vue-meta (Vue 2)
export default {
  metaInfo() {
    return {
      title: 'My Page',
      meta: [
        { name: 'description', content: 'Page description' }
      ]
    }
  }
}
// Unhead (Vue 3)
useSeoMeta({
  title: 'My Page',
  description: 'Page description'
})

Unhead's useSeoMeta() flattens the nested structure. No more meta arrays with name/content objects.

Syntax Mapping

vue-metaUnheadNotes
metaInfo: {}useHead({})Static object
metaInfo()useHead({}) with refsReactive by default
titletitleSame
titleTemplate: '%s - Site'titleTemplate: '%s - Site'Same
meta: [{ name, content }]useSeoMeta({ name: value })Flattened
vmid / hidkeyFor deduplication
childreninnerHTMLScript content
body: truetagPosition: 'bodyClose'Script positioning

Migration Steps

1. Remove vue-meta

npm uninstall vue-meta
npm install @unhead/vue

2. Update Plugin Setup

import Vue from 'vue'
import VueMeta from 'vue-meta'

Vue.use(VueMeta)

For SSR apps, import from @unhead/vue/server instead:

import { createHead } from '@unhead/vue/server'

3. Convert Components

<script>
export default {
  data() {
    return { pageTitle: 'About Us' }
  },
  metaInfo() {
    return {
      title: this.pageTitle,
      titleTemplate: '%s | MySite',
      meta: [
        { name: 'description', content: 'About our company' },
        { property: 'og:title', content: this.pageTitle },
        { property: 'og:description', content: 'About our company' }
      ]
    }
  }
}
</script>

4. Search and Replace Patterns

FindReplace
metaInfo() or metaInfo: {useHead({ or useSeoMeta({
this.$meta().refresh()Remove (automatic)
vmid:key:
hid:key:
{ name: 'description', content:description: (in useSeoMeta)
{ property: 'og:title', content:ogTitle: (in useSeoMeta)

Breaking Changes

Reactivity Model

vue-meta required metaInfo() as a function for reactivity. Unhead is reactive by default—pass refs directly:

// vue-meta: function required for reactivity
export default {
  metaInfo() {
    return { title: this.dynamicTitle }
  }
}
// Unhead: refs work automatically
const dynamicTitle = ref('Loading...')
useHead({ title: dynamicTitle })

No Implicit Context After Async

Unhead v2 removed implicit context. Don't call useHead() after await without saving the head instance:

// ❌ May fail in Unhead v2
async function loadData() {
  const data = await fetchData()
  useHead({ title: data.title }) // Context lost
}

// ✅ Call before await or use injectHead()
const head = injectHead()
async function loadData() {
  const data = await fetchData()
  head.push({ title: data.title })
}

SSR Rendering

vue-meta had inject() for SSR. Unhead uses renderSSRHead():

// Server entry
import { renderSSRHead } from '@unhead/ssr'

const { headTags, bodyTags, bodyTagsOpen, htmlAttrs, bodyAttrs } = await renderSSRHead(head)

Template Params Plugin

titleTemplate params like %separator require explicit plugin registration in Unhead v2:

import { createHead } from '@unhead/vue/client'
import { TemplateParamsPlugin } from '@unhead/vue/plugins'

const head = createHead({
  plugins: [TemplateParamsPlugin]
})

Why Migrate?

vue-metaUnhead
Last stable: 2021Actively maintained
Vue 2 onlyVue 3 native
30KB+~8KB gzipped
Limited TypeScriptFull type safety
Community abandonedOfficial Nuxt ecosystem

Unhead also provides useSeoMeta() with autocomplete for all SEO properties—no more guessing meta tag names.

If you're using Nuxt, you don't need to install Unhead separately. It's built in. See Nuxt SEO for Nuxt-specific setup.