---
title: "useSeoMeta Transform"
description: "Convert useSeoMeta() calls to useHead() at build time and avoid runtime meta-key resolution."
canonical_url: "https://unhead.unjs.io/docs/head/guides/build-plugins/seo-meta-transform"
last_updated: "2026-08-11T00:44:03.018Z"
---

The `useSeoMeta` transform rewrites statically analyzable `useSeoMeta()` calls into equivalent `useHead()` calls at build time. This can remove runtime meta-key resolution code from the bundle. The transform is enabled by default and also handles the deprecated `useServerSeoMeta()`.

## Transformation

At build time, `useSeoMeta()` calls with static or semi-static arguments are converted to `useHead()` with pre-resolved `meta` arrays:

<code-group>

```ts [Before (source)]
useSeoMeta({
  title: 'My Title',
  description: 'My Description',
  ogImage: 'https://example.com/image.png',
})
```

```ts [After (build output)]
useHead({
  title: 'My Title',
  meta: [
    { name: 'description', content: 'My Description' },
    { property: 'og:image', content: 'https://example.com/image.png' },
  ],
})
```

</code-group>

When a call is transformed, its import specifier is also rewritten: `import { useSeoMeta } from 'unhead'` becomes `import { useHead } from 'unhead'`.

## Setup

The transform is enabled by default when using the [unified Vite plugin](/docs/head/guides/build-plugins/overview):

```ts
import { Unhead } from '@unhead/vue/vite'

export default defineConfig({
  plugins: [Unhead()],
})
```

### Disable

```ts
Unhead({
  transformSeoMeta: false,
})
```

## Options

```ts
Unhead({
  transformSeoMeta: {
    // Disable import specifier rewriting
    imports: false,
    // Extra import paths to recognize as useSeoMeta sources
    importPaths: ['my-custom-package'],
    // Override the shared file filter
    filter: {
      include: [/my-special-file/],
      exclude: [/some-file/],
    },
  },
})
```

<table>
<thead>
  <tr>
    <th>
      Option
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        imports
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Rewrite import specifiers (<code>
        useSeoMeta
      </code>
      
       → <code>
        useHead
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        importPaths
      </code>
    </td>
    
    <td>
      <code>
        string[]
      </code>
    </td>
    
    <td>
      Unset
    </td>
    
    <td>
      Additional package names to treat as valid <code>
        useSeoMeta
      </code>
      
       sources
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        filter
      </code>
    </td>
    
    <td>
      <code>
        object
      </code>
    </td>
    
    <td>
      inherited
    </td>
    
    <td>
      Include/exclude file patterns (overrides the shared <code>
        filter
      </code>
      
      )
    </td>
  </tr>
</tbody>
</table>

## Limitations

The transform skips calls it cannot statically analyze:

- A non-object or dynamic first argument
- Spread elements in the options object (`useSeoMeta({ ...dynamicMeta })`)
- Non-identifier keys
- Properties with missing values
- Packed object fields such as `robots` whose keys or values are not static strings
- Structured media objects whose shape uses spreads, computed keys, getters, setters, or methods. Their leaf values may be dynamic when the object shape itself is static

In these cases, the original `useSeoMeta()` call is preserved and resolved at runtime.

### Deprecated `useServerSeoMeta`

The transform also handles the deprecated `useServerSeoMeta()`. When it includes `title` or `titleTemplate`, the transform splits the call into two: a `useHead()` call for the title fields and a `useServerHead()` call for the meta tags.

```ts
// Input (deprecated)
useServerSeoMeta({ title: 'My Title', description: 'My Desc' })

// Output
useHead({ title: 'My Title' })
useServerHead({ meta: [{ name: 'description', content: 'My Desc' }] })
```

New code should use `useSeoMeta()` instead.
