Upgrade Guide
Migrate to v3 (from v2)
Unhead v3 removes all deprecated APIs and focuses on performance improvements. This guide covers the breaking changes for Vue users.
Legacy Property Names
🚦 Impact Level: High
The DeprecationsPlugin that automatically converted legacy property names has been removed. You must update your head entries to use the current property names.
children → innerHTML
useHead({
script: [{
- children: 'console.log("hello")',
+ innerHTML: 'console.log("hello")',
}]
})
hid / vmid → key
useHead({
meta: [{
- hid: 'description',
+ key: 'description',
name: 'description',
content: 'My description'
}]
})
body: true → tagPosition: 'bodyClose'
useHead({
script: [{
src: '/script.js',
- body: true,
+ tagPosition: 'bodyClose',
}]
})
Schema.org Plugin
🚦 Impact Level: High
The PluginSchemaOrg and SchemaOrgUnheadPlugin exports have been removed. Use UnheadSchemaOrg instead.
- import { PluginSchemaOrg } from '@unhead/schema-org/vue'
+ import { UnheadSchemaOrg } from '@unhead/schema-org/vue'
const head = createHead({
plugins: [
- PluginSchemaOrg()
+ UnheadSchemaOrg()
]
})
Server Composables Removed
🚦 Impact Level: Medium-High
The useServerHead, useServerHeadSafe, and useServerSeoMeta composables have been removed. Use the standard composables instead.
- import { useServerHead, useServerSeoMeta } from '@unhead/vue'
+ import { useHead, useSeoMeta } from '@unhead/vue'
- useServerHead({ title: 'My Page' })
+ useHead({ title: 'My Page' })
- useServerSeoMeta({ description: 'My description' })
+ useSeoMeta({ description: 'My description' })
If you need server-only head management, use conditional logic:
if (import.meta.server) {
useHead({ title: 'Server Only' })
}
Vue Legacy Exports Removed
🚦 Impact Level: Medium
The /legacy export path has been removed from @unhead/vue.
- import { createHead } from '@unhead/vue/legacy'
+ import { createHead } from '@unhead/vue/client'
// or for SSR
+ import { createHead } from '@unhead/vue/server'
createHeadCore Removed
- import { createHeadCore } from '@unhead/vue'
+ import { createHead } from '@unhead/vue/server'
// or for client
+ import { createHead } from '@unhead/vue/client'
Core API Changes
🚦 Impact Level: Medium
headEntries() → entries Map
- const entries = head.headEntries()
+ const entries = [...head.entries.values()]
mode Option Removed
The mode option on head entries has been removed.
useHead({
title: 'My Page',
- }, { mode: 'server' })
+ })
Hooks
🚦 Impact Level: Low
The following hooks have been removed:
init- No longer neededdom:renderTag- DOM rendering is now synchronousdom:rendered- Use code afterrenderDOMHead()instead
The dom:beforeRender hook is now synchronous and renderDOMHead no longer returns a Promise:
- await renderDOMHead(head, { document })
+ renderDOMHead(head, { document })
The SSR hooks (ssr:beforeRender, ssr:render, ssr:rendered) are now synchronous and renderSSRHead no longer returns a Promise:
- const head = await renderSSRHead(head)
+ const head = renderSSRHead(head)
Other Removed APIs
resolveUnrefHeadInput- Reactive resolution now happens automaticallysetHeadInjectionHandler- Head injection is handled automaticallyDeprecationsPlugin- Update property names directly instead
Type Changes
🚦 Impact Level: Low
- import type { Head, MetaFlatInput } from '@unhead/vue'
+ import type { HeadTag, MetaFlat } from '@unhead/vue'
Migrate to v2 (from v1)
With the release of Unhead v2, we now have first-class support for other frameworks. This section covers the v1 to v2 migration for Vue users.
Client / Server Subpath Exports
🚦 Impact Level: Critical
⚠️ Breaking Changes:
createServerHead()andcreateHead()exports fromunheadare removed
The path where you import createHead from has been updated to be a subpath export.
Client bundle:
-import { createHead } from '@unhead/vue'
+import { createHead } from '@unhead/vue/client'
import { createApp } from 'vue'
const app = createApp()
const head = createHead()
app.use(head)
Server bundle:
-import { createServerHead } from '@unhead/vue'
+import { createHead } from '@unhead/vue/server'
import { createApp } from 'vue'
const app = createApp()
-const head = createServerHead()
+const head = createHead()
app.use(head)
Removed Implicit Context
🚦 Impact Level: Critical
⚠️ Breaking Changes:
setHeadInjectionHandler()is removed- Error may be thrown when using
useHead()after async operations
The implicit context implementation kept a global instance of Unhead available so that you could use the useHead() composables anywhere in your application.
In v2, the core composables no longer have access to the Unhead instance. Instead, you must pass the Unhead instance to the composables if you'd like to use Unhead in a non-Vue context.
<script setup lang="ts">
// In Vue this happens in lifecycle hooks where we have async operations.
onMounted(async () => {
await fetchSomeData()
useHead({
title: 'This will not work'
})
})
</script>
If you're getting errors on your useHead() about context, check the Reactivity and Async Context guide.
Removed vmid, hid, children, body
🚦 Impact Level: High
For legacy support with Vue Meta we allowed end users to provide deprecated properties: vmid, hid, children and body.
You must update these properties to the appropriate replacement or remove them. See the v3 migration section for the replacements.
Opt-in Template Params & Tag Alias Sorting
🚦 Impact Level: High
To reduce the bundle size and improve performance, we've moved the template params and tag alias sorting to optional plugins.
import { AliasSortingPlugin, TemplateParamsPlugin } from '@unhead/vue/plugins'
createHead({
plugins: [TemplateParamsPlugin, AliasSortingPlugin]
})
Vue 2 Support
🚦 Impact Level: Critical
Unhead v2 no longer supports Vue v2. If you're using Vue v2, you will need to lock your dependencies to the latest v1 version of Unhead.
Promise Input Support
🚦 Impact Level: Medium
If you have promises as input they will no longer be resolved, either await the promise before passing it along or register the optional promises plugin.
import { createHead } from '@unhead/vue/client'
import { PromisePlugin } from '@unhead/vue/plugins'
const unhead = createHead({
plugins: [PromisePlugin]
})
Updated useScript()
🚦 Impact Level: High
⚠️ Breaking Changes:
- Script instance is no longer augmented as a proxy and promise
script.proxyis rewritten for simpler, more stable behaviorstub()and runtime hookscript:instance-fnare removed
Replacing promise usage
const script = useScript()
-script.then(() => console.log('loaded')
+script.onLoaded(() => console.log('loaded'))
Replacing proxy usage
const script = useScript('..', {
use() { return { foo: [] } }
})
-script.foo.push('bar')
+script.proxy.foo.push('bar')
Tag Sorting Updated
🚦 Impact Level: Low
Capo.js sorting is now the default. You can opt-out:
createHead({
disableCapoSorting: true,
})
Default SSR Tags
🚦 Impact Level: Low
When SSR Unhead will now insert important default tags for you:
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><html lang="en">
import { createHead } from '@unhead/vue/server'
// disable when creating the head instance
createHead({
disableDefaults: true,
})
Or override the defaults:
import { useHead } from '@unhead/vue'
useHead({
htmlAttrs: {
lang: 'fr'
}
})
CJS Exports Removed
🚦 Impact Level: Low
CommonJS exports have been removed in favor of ESM only.
-const { useHead } = require('@unhead/vue')
+import { useHead } from '@unhead/vue'
Deprecated @unhead/schema
🚦 Impact Level: Low
The @unhead/schema package is deprecated. Import from @unhead/vue/types instead.
-import { HeadTag } from '@unhead/schema'
+import { HeadTag } from '@unhead/vue/types'