Does useHead not exist in Nuxt 4?

If it does, what is the correct syntax for using it in the app page, I just updated Nuxt 3 to Nuxt 4 and am seeing a TS error with the useHead. What am I doing wrong?
7 Replies
kapa.ai
kapa.ai2mo ago
Hi @Sagar Kapoor. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Yes, useHead does exist in Nuxt 4. However, there are some important changes and migration steps you need to be aware of when upgrading from Nuxt 3 to Nuxt 4, especially regarding how you import and use useHead. Key Points for Nuxt 4 - useHead is still available and is the recommended way to manage head/meta tags. - Imports: In Nuxt 4, you should use the auto-imported useHead (or import from #imports or nuxt/app), not from @unhead/vue. Importing from @unhead/vue will not work outside of Vue context (e.g., in plugins or middleware) and can cause errors. This is a breaking change from previous versions where such imports might have worked. - TypeScript Changes: The types for useHead have changed. In Nuxt 4, useHead() always returns an ActiveHeadEntry (not void), and the types are stricter. If you see a TS error, it may be due to passing a function where a plain object or a computed value is expected. Correct Usage Example in app.vue
<script setup lang="ts">
const title = ref('My App')
const description = ref('My App Description')

// This will be reactive when you change title/description above
useHead({
title,
meta: [{
name: 'description',
content: description
}]
})
</script>
<script setup lang="ts">
const title = ref('My App')
const description = ref('My App Description')

// This will be reactive when you change title/description above
useHead({
title,
meta: [{
name: 'description',
content: description
}]
})
</script>
If you need to use computed or reactive values for properties like htmlAttrs, wrap the entire object in a computed and pass it to useHead:
<script setup lang="ts">
const localeHead = ref({
htmlAttrs: { lang: 'en' },
link: [],
meta: []
})
useHead(
computed(() => ({
htmlAttrs: localeHead.value.htmlAttrs,
link: localeHead.value.link,
meta: localeHead.value.meta
}))
)
</script>
<script setup lang="ts">
const localeHead = ref({
htmlAttrs: { lang: 'en' },
link: [],
meta: []
})
useHead(
computed(() => ({
htmlAttrs: localeHead.value.htmlAttrs,
link: localeHead.value.link,
meta: localeHead.value.meta
}))
)
</script>
This approach avoids the TypeScript error you might see if you try to pass a function directly to a property like htmlAttrs instead of wrapping the whole object in a computed. This is confirmed as a solution in a real-world issue after upgrading to Nuxt 4 [Nuxt useHead TypeError]. Summary of What Might Be Wrong - Importing from @unhead/vue instead of using the Nuxt auto-import or #imports. - Passing a function to a property (e.g., htmlAttrs: () => ...) instead of wrapping the whole object in a computed and passing that to useHead. - Not updating your code to match the stricter types in Nuxt 4. For more details, see the migration notes and examples in the official documentation and related issues [Unhead v2 Upgrade Guide], [Nuxt useHead TypeError], [feat(nuxt): upgrade Unhead v2 major]. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@565461230060306432> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Sagar Kapoor
Sagar KapoorOP2mo ago
@kapa.ai
useHead({
htmlAttrs: {
lang: "bg",
},

titleTemplate: (titleChunk) => {
return titleChunk ? `${titleChunk} | Name` : "Name";
},
});
useHead({
htmlAttrs: {
lang: "bg",
},

titleTemplate: (titleChunk) => {
return titleChunk ? `${titleChunk} | Name` : "Name";
},
});
Is this approach wrong?
kapa.ai
kapa.ai2mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Your approach is correct for using useHead in Nuxt, and the syntax you provided is valid:
useHead({
htmlAttrs: {
lang: "bg",
},
titleTemplate: (titleChunk) => {
return titleChunk ? `${titleChunk} | Name` : "Name";
},
});
useHead({
htmlAttrs: {
lang: "bg",
},
titleTemplate: (titleChunk) => {
return titleChunk ? `${titleChunk} | Name` : "Name";
},
});
- Setting htmlAttrs as an object is the recommended way to set attributes like lang on the <html> tag. - Using a function for titleTemplate is also supported, but note that this cannot be set in your nuxt.config—it should be set in a file like app.vue or a layout, as you are doing here. This is explicitly recommended in the documentation for dynamic title templates [SEO and Meta Features]. If you are seeing a TypeScript error, it is likely due to how the function is being passed or a mismatch in types elsewhere, but the structure you posted matches the documented usage for Nuxt 3 and Nuxt 4 [useHead API]. Summary:
Your approach is correct and matches the official Nuxt documentation. If you encounter errors, double-check that you are not placing this in nuxt.config and that you are using the correct import or auto-import for useHead in your setup file. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@565461230060306432> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
harlan
harlan2mo ago
what's the error?
Sagar Kapoor
Sagar KapoorOP2mo ago
Got it working, since I am using docker with Taskfile, I realised the project was being built in another docker container, fixed it and the TS errors disappeared, it was a silly error. 😅 Good to see you here though!

Did you find this page helpful?