Skip to content

Bump @unhead/vue to v3 for Nuxt 4.5 compatibility #6765

Description

@ChristopheCVB

Description

With Nuxt 4.5.0, Nuxt migrated to Unhead v3 (renderSSRHead is synchronous). @nuxt/ui@4.10.0 still depends on @unhead/vue@^2.1.15, which pulls Unhead v2 into the install tree.

In a Nuxt 4.5 + Nuxt UI app, Nitro can trace both versions into the server output:

.output/server/node_modules/.nitro/unhead@2.1.16/
.output/server/node_modules/.nitro/unhead@3.2.2/
.output/server/node_modules/unhead -> .nitro/unhead@2.1.16   # wrong

Nuxt's SSR renderer imports bare unhead/server and calls renderSSRHead without await (v3 API). Resolving v2's async renderSSRHead means the Promise is destructured instead of the head result, so all SSR head tags are dropped — including the client entry <script type="module" src="/_nuxt/...">.

Impact

  • Production builds serve HTML with no client JS (hydration never starts)
  • Apps look “SSR-only” / non-interactive
  • Playwright/@nuxt/test-utils e2e with { waitUntil: 'hydration' } times out (window.useNuxtApp never appears)

This is not limited to tests; it affects the production Nitro output.

Environment

  • nuxt: ^4.5.0 (resolved 4.5.0)
  • @nuxt/ui: 4.10.0 (latest at report time)
  • Package manager: bun
  • @nuxt/ui declares: "@unhead/vue": "^2.1.15"

Reproduction

  1. Create/use a Nuxt 4.5 app with @nuxt/ui
  2. Do not override @unhead/vue / unhead
  3. nuxt build (or e2e build via @nuxt/test-utils)
  4. Inspect .output/server/node_modules/unhead (symlink target) and curl /
  5. Observe missing /_nuxt/ entry script in HTML when the v2 symlink wins

Workaround

Force a single Unhead v3 resolution (works for us with bun):

{
  "overrides": {
    "@unhead/vue": "^3.2.2",
    "unhead": "^3.2.2"
  }
}

After that, .output/server/node_modules/unhead resolves to 3.2.2, entry scripts return, and hydration works again.

Expected

@nuxt/ui should depend on (or peer on) @unhead/vue v3 aligned with Nuxt 4.5+, so consumers do not need overrides.

Nuxt UI already appears runtime-compatible with Unhead v3 in places (e.g. nuxt/ui#6658 avoided v2-only hookOnce), so this looks primarily like a dependency pin that still forces Unhead v2 into the tree.

Additional context

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions