---
title: "Installing Unhead with React"
description: "Set up Unhead in React with UnheadProvider and the useHead() hook. Includes a compatibility path for migrating from react-helmet."
canonical_url: "https://unhead.unjs.io/docs/react/head/guides/get-started/installation"
last_updated: "2026-07-21T05:10:37.980Z"
---

Install `@unhead/react`, wrap the application with `UnheadProvider`, and call `useHead()` in components. For SSR, inject the rendered tags with `transformHtmlTemplate()`.

Use the `<Head>` component for JSX-style declarations or `useHead()` for object input. If you are migrating from [`react-helmet`](https://github.com/nfl/react-helmet), Unhead also ships a compatibility component.

The examples follow [Vite's SSR structure](https://vite.dev/guide/ssr.html); the same client entry point works in a React SPA.

## Demos

- [StackBlitz - Unhead - Vite + React SSR](https://stackblitz.com/edit/github-5hqsxyid)
- [StackBlitz - Unhead - React SPA](https://stackblitz.com/edit/vitejs-vite-ggqxj5nx)

## Install Unhead

### 1. Add Dependency

Install the `@unhead/react` dependency in your project.

<module-install name="@unhead/react@next">



</module-install>

### 2. Set Up Client-Side Rendering

Create the browser instance from `@unhead/react/client`. In a Vite SSR app this usually belongs in `entry-client.ts`; in an SPA, put it in the main entry.

```tsx [src/entry-client.ts]
import { createHead, UnheadProvider } from '@unhead/react/client'
import { StrictMode } from 'react'
import { hydrateRoot } from 'react-dom/client'
import App from './App'
import './index.css'

const head = createHead()

hydrateRoot(
  document.getElementById('root') as HTMLElement,
  <StrictMode>
    <UnheadProvider head={head}>
      <App />
    </UnheadProvider>
  </StrictMode>,
)
```

### 3. Set Up Server-Side Rendering

<note>

Serving your app as an SPA? You can [skip](#4-add-head-tags) this step.

</note>

For SSR, create a fresh instance from `@unhead/react/server` for each request and return it with the rendered app.

```tsx [src/entry-server.ts]
import { createHead, UnheadProvider } from '@unhead/react/server'
import { StrictMode } from 'react'
import { renderToString } from 'react-dom/server'
import App from './App'

export function render(_url: string) {
  const head = createHead()
  const html = renderToString(
    <StrictMode>
      <UnheadProvider value={head}>
        <App />
      </UnheadProvider>
    </StrictMode>,
  )
  return { html, head }
}
```

After React renders, pass the instance and complete HTML template to `transformHtmlTemplate()`:

```ts [server.ts]
import { transformHtmlTemplate } from '@unhead/react/server'
// ...

// Serve HTML
app.use('*all', async (req, res) => {
  try {
    // ...

    const rendered = await render(url)

    const html = transformHtmlTemplate(
      rendered.head,
      template.replace(`<!--app-html-->`, rendered.html ?? '')
    )

    res.status(200).set({ 'Content-Type': 'text/html' }).send(html)
  }
  catch (e) {
    // ...
  }
})
// ..
```

### 4. Add Head Tags

The server head inserts three defaults:

- `<meta charset="utf-8">`
- `<meta name="viewport" content="width=device-width, initial-scale=1">`
- `<html lang="en">`

Set server-only defaults through `init`. Keeping them in the server entry also keeps them out of the client bundle.

```ts [src/entry-server.ts]
import { createHead } from '@unhead/react/server'

export function render(_url: string) {
  const head = createHead({
    // change default initial lang
    init: [
      {
        htmlAttrs: { lang: 'en' },
        title: 'Default title',
        titleTemplate: '%s - My Site',
      },
    ]
  })
  const html = `<!-- your html -->`
  return { html, head }
}
```

To add tags in your components, use either the `<Head>` component or the `useHead()` hook.

- `useHead()` accepts the full typed head object and entry options.
- `<Head>` accepts native head elements as children.

```tsx [App.tsx]
import { Head, useHead } from '@unhead/react'

export default function App() {
  // a. use the hook
  useHead({
    title: 'Example Site',
    meta: [
      { name: 'description', content: 'An example page description.' }
    ]
  })
  // b. use the component
  return (
    <div>
      <Head>
        <title>Example Site</title>
        <meta name="description" content="An example page description." />
      </Head>
      <h1>Hello World</h1>
    </div>
  )
}
```

### 5. Enable Auto-Imports (Optional)

[unplugin-auto-import](https://github.com/unplugin/unplugin-auto-import) can provide the composables without explicit imports:

```ts [vite.config.ts]
import { hookImports } from '@unhead/react'
import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  plugins: [
    AutoImport({
      imports: [
        hookImports,
      ],
    }),
    // ...
  ]
})
```

## Next Steps

Hooks and components:

- [`useHead()`](/docs/head/api/composables/use-head)
- [`useSeoMeta()`](/docs/head/api/composables/use-seo-meta)

For `react-helmet`, see the [migration guide](/docs/react/head/guides/get-started/migrate-from-react-helmet).

Optional integrations:

- Add [`useSchemaOrg()`](/docs/schema-org/api/composables/use-schema-org) for structured data
- Use [`useScript()`](/docs/head/api/composables/use-script) for loading triggers and script lifecycle hooks
