{"id":12280,"library":"unhead","title":"Unhead: Universal Head Manager","description":"Unhead is a full-stack, framework-agnostic head manager designed to simplify and standardize how metadata (like `<title>`, `<meta>`, `<link>`) is managed in JavaScript applications. It is currently at version 3.0.4, with frequent patch releases addressing bug fixes and minor improvements, and major versions (like the recent v3.0.0) introducing significant architectural changes, such as the rebuild for streaming SSR. Its key differentiators include comprehensive framework agnosticism, reactive head management, robust server-side rendering support with a focus on streaming capabilities, SEO-friendliness, type safety via TypeScript, and a lightweight, tree-shakable design optimized for performance with minimal runtime overhead. It integrates seamlessly with popular frameworks through dedicated packages like `@unhead/vue` and `@unhead/react`.","status":"active","version":"3.0.4","language":"javascript","source_language":"en","source_url":"https://github.com/unjs/unhead","tags":["javascript","typescript"],"install":[{"cmd":"npm install unhead","lang":"bash","label":"npm"},{"cmd":"yarn add unhead","lang":"bash","label":"yarn"},{"cmd":"pnpm add unhead","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for framework integrations and specific build optimizations, especially for server-side rendering and development mode. This is a peer dependency.","package":"vite","optional":true}],"imports":[{"note":"Primary function to initialize a new head instance. CommonJS `require` is not directly supported since v3, which is ESM-only.","wrong":"const { createHead } = require('unhead')","symbol":"createHead","correct":"import { createHead } from 'unhead'"},{"note":"Used to add head entries to the active head instance. While framework-specific wrappers exist (e.g., `@unhead/vue`), the core `useHead` is from `unhead` directly when using the generic API. Incorrectly importing from framework packages can lead to unexpected behavior.","wrong":"import useHead from 'unhead/vue'","symbol":"useHead","correct":"import { useHead } from 'unhead'"},{"note":"When performing Server-Side Rendering (SSR), it's crucial to import `createHead` from `unhead/server` to ensure the correct SSR-optimized instance is used for rendering head tags synchronously and with streaming support. Using the client-side `createHead` in an SSR context will not yield the desired output.","wrong":"import { createHead } from 'unhead'","symbol":"createHead (SSR)","correct":"import { createHead } from 'unhead/server'"}],"quickstart":{"code":"import { createHead, useHead } from 'unhead';\n\n// 1. Create a head instance. For SSR, use `createHead` from 'unhead/server'.\nconst head = createHead();\n\n// 2. Add reactive head entries using `useHead`.\n// This example updates the title and adds a meta description.\nuseHead({\n  title: 'My Dynamic App Title',\n  meta: [\n    { name: 'description', content: 'This is a dynamic description for my awesome application.' },\n    { property: 'og:title', content: 'Open Graph Title' }\n  ],\n  link: [\n    { rel: 'canonical', href: 'https://example.com/my-page' }\n  ],\n  script: [\n    { src: 'https://unpkg.com/some-script.js', defer: true, body: true }\n  ]\n}, { head });\n\n// 3. For SSR, render the head tags.\n// In a real SSR environment, you'd call this after all components have rendered.\nconst { headTags, bodyTags } = head.renderSync();\n\nconsole.log('Generated Head Tags:\\n', headTags);\nconsole.log('Generated Body Tags (scripts in body):\\n', bodyTags);\n\n// Output example (simplified):\n// <title>My Dynamic App Title</title>\n// <meta name=\"description\" content=\"This is a dynamic description for my awesome application.\">\n// ...\n// <script src=\"https://unpkg.com/some-script.js\" defer></script>","lang":"typescript","description":"This quickstart demonstrates how to create a head instance, add common head elements (title, meta, link, script) using `useHead`, and then synchronously render the collected head and body tags, which is typically done in a Server-Side Rendering (SSR) context."},"warnings":[{"fix":"Review the v3 migration guide on the Unhead documentation site. Update `head.render()` calls to `head.renderSync()` where applicable for SSR. Adapt custom renderers and plugins to the new synchronous, pluggable architecture. Ensure CommonJS `require` statements are replaced with ESM `import` statements.","message":"Unhead v3.0.0 introduces a complete rebuild of the rendering engine to support streaming SSR. This change makes rendering synchronous, pluggable, and side-effect free. Existing v2 code relying on asynchronous rendering or specific internal behaviors will break. The core API for `render` became `renderSync`.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Upgrade to `unhead` version 2.1.11 or later immediately, especially if your application handles untrusted input with `useHeadSafe`.","message":"A security vulnerability (XSS bypass via attribute name injection) was fixed in v2.1.11 when using `useHeadSafe`. This could allow malicious script injection if `useHeadSafe` was used with untrusted user input.","severity":"gotcha","affected_versions":"<2.1.11"},{"fix":"Upgrade to `unhead` version 2.1.12 or later to mitigate potential prototype pollution risks.","message":"Unhead v2.1.12 included a fix for prototype pollution. While not explicitly detailed as an exploit, prototype pollution vulnerabilities can lead to various security issues, including arbitrary code execution or denial of service.","severity":"gotcha","affected_versions":"<2.1.12"},{"fix":"Always use ES module `import` syntax (e.g., `import { createHead } from 'unhead'`). Ensure your project is configured for ESM or use a bundler that correctly handles ESM imports.","message":"Since v3, Unhead is primarily an ESM-first package. Attempting to use `require()` for imports will lead to errors in most modern Node.js environments unless specific transpilation or module resolution configurations are in place.","severity":"gotcha","affected_versions":">=3.0.0"},{"fix":"For server-side rendering, always import `createHead` from `unhead/server` (e.g., `import { createHead } from 'unhead/server'`). For client-side rendering, use `unhead/client`.","message":"In v3, the main `unhead` package for SSR context changed its export path. While `v3.0.3` restored some legacy exports for migration, relying on `createHead` from the root `unhead` package for SSR is generally incorrect.","severity":"deprecated","affected_versions":">=3.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Change `head.render()` to `head.renderSync()` for synchronous SSR rendering.","cause":"Attempting to call `render()` on a `head` instance created with v3, where `render` was renamed to `renderSync`.","error":"TypeError: head.render is not a function"},{"fix":"Update your import statements to use ES Module syntax: `import { createHead, useHead } from 'unhead'`.","cause":"Attempting to import `unhead` using CommonJS `require()` syntax in an environment where `unhead` is distributed as an ES Module.","error":"Error [ERR_REQUIRE_ESM]: require() of ES Module ... unhead/index.mjs not supported."},{"fix":"Upgrade Unhead to the latest v3 patch version (e.g., v3.0.4 or later) as recent fixes address `readonly` inputs and string widening issues. Ensure custom `rel` or `type` attributes are correctly typed as `string & {}` or use `as const` for literals to prevent widening.","cause":"Type widening in older Unhead versions or incorrect type definitions being passed, preventing proper type inference for specific meta attributes or elements. Might also occur if using a custom `rel` or `type` without proper type narrowing escape hatches.","error":"Property 'title' does not exist on type 'HeadEntryOptions' or similar TypeScript errors when defining head elements."},{"fix":"Ensure you are using `unhead` version 3.0.3 or higher if you are experiencing inconsistent head tag updates or hydration issues in a Vite development environment.","cause":"In `v3.0.3`, a bug was fixed where `SSRStaticReplace` was improperly disabled in Vite dev mode, leading to potential inconsistencies between server-rendered and client-hydrated head content.","error":"Vite dev mode issues with head tags not updating correctly or SSR hydration mismatches."}],"ecosystem":"npm"}