Index of every page on this site: llms.txt

Migrating from vue-meta to Unhead

Migrate from vue-meta to Unhead in Vue 3, with syntax mapping, breaking changes, and search-and-replace patterns.
Harlan Wilton6 mins read Published Updated
What you'll learn
  • vue-meta never shipped stable 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

If your app uses Vue 2, migrate the framework to Vue 3 before following these Unhead examples.

vue-meta was the standard for Vue 2 head management but never shipped a stable Vue 3 version: it stalled at a 3.0.0-alpha release. The repository was archived in October 2025 after years without updates. Unhead is its modern replacement, built by the same ecosystem and Vue 3 native from the start.

Quick Comparison

export default {
  metaInfo() {
    return {
      title: 'My Page',
      meta: [
        { name: 'description', content: 'Page description' }
      ]
    }
  }
}

Unhead's useSeoMeta() replaces nested meta arrays and name/content objects with flat properties.

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 lang="ts">
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, so pass refs directly:

<script lang="ts">
// vue-meta: function required for reactivity
export default {
  metaInfo() {
    return { title: this.dynamicTitle }
  }
}
</script>

No Implicit Context After Async

Unhead v2 removed implicit context. These examples are component-setup excerpts; fetchData is your application's data loader. Don't call useHead() after await without saving the head instance:

import { useHead } from '@unhead/vue'

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

SSR Rendering

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

// Excerpt: head is the request-owned instance installed on your SSR app.
import { renderSSRHead } from '@unhead/vue/server'

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 release: 2020Actively maintained
Vue 2 onlyVue 3 native
Limited TypeScriptFull type safety
Community abandonedOfficial Nuxt ecosystem

Unhead also provides useSeoMeta() with autocomplete for all SEO properties, so there's 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.

Checklist

Checklist
  • Uninstalled vue-meta and installed @unhead/vue
  • Replaced Vue.use(VueMeta) with createHead() and app.use(head)
  • Converted every metaInfo() block to useHead() or useSeoMeta()
  • Renamed vmid/hid fields to key
  • Pass refs and computed getters directly to useHead(), not .value
  • Call useHead() before an await, or use injectHead() to keep context after async code
  • Registered TemplateParamsPlugin() if you use custom titleTemplate params like %separator
Was this page helpful?