---
title: "useSeoMeta Transform"
description: "Convert useSeoMeta() calls to useHead() at build time, saving ~3kb from your client bundle."
canonical_url: "https://unhead.unjs.io/docs/head/guides/build-plugins/seo-meta-transform"
last_updated: "2026-06-30T06:50:22.832Z"
---

**Quick Answer:** The `useSeoMeta` transform rewrites `useSeoMeta()` calls into equivalent `useHead()` calls at build time. This removes the runtime meta-key resolution code (~3kb) from your bundle. Enabled by default. Also handles the deprecated `useServerSeoMeta()` for legacy code.

## What Does It Do?

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>

Import specifiers are 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>
      —
    </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:

- Spread elements in the options object (`useSeoMeta({ ...dynamicMeta })`)
- Non-identifier keys
- Properties with missing values
- Object-valued properties with non-static (non-string-literal) sub-properties

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.
