Migration Guides

v5 to v6

Last updated by Harlan Wilton in feat!: native tailwind v4 support (#430).

Quick Migration

Run the migration CLI to automate most changes:

# Rename components and migrate API calls
npx nuxt-og-image migrate v6

# Preview changes without applying (dry run)
npx nuxt-og-image migrate v6 --dry-run

This will:

  • Rename components/OgImage/*.vue to include renderer suffix (e.g., .satori.vue)
  • Migrate defineOgImageComponent() calls to defineOgImage()

Component Renderer Suffix Required

Breaking: OG Image components must now include a renderer suffix in their filename.

# Before (no longer works)
components/OgImage/MyTemplate.vue

# After
components/OgImage/MyTemplate.satori.vue   # for Satori renderer
components/OgImage/MyTemplate.takumi.vue   # for Takumi renderer
components/OgImage/MyTemplate.chromium.vue # for Chromium renderer

This change enables:

  • Automatic renderer detection from filename
  • Multiple renderer variants of the same component
  • Tree-shaking of unused renderer code

The CLI migration command will rename your components automatically:

npx nuxt-og-image migrate v6

Multiple Renderers Per Component

You can now create renderer-specific variants of the same component:

components/OgImage/
  MyTemplate.satori.vue    # Complex version for Satori
  MyTemplate.takumi.vue    # Simplified version for Takumi (faster)

When calling defineOgImage('MyTemplate', ...), the module selects the variant matching the configured renderer.

defineOgImageComponent Deprecated

The defineOgImageComponent() composable is deprecated. Use defineOgImage() with the component name as the first argument:

- defineOgImageComponent('NuxtSeo', { title: 'Hello' }, { fonts: ['Inter'] })
+ defineOgImage('NuxtSeo', { title: 'Hello' }, { fonts: ['Inter'] })

The API is identical - just remove "Component" from the function name. The migration CLI handles this automatically.

Nuxt Content v2 Support Removed

Nuxt Content v2 is no longer supported. If you're using @nuxt/content, you must upgrade to v3 or later.

The automatic ogImage frontmatter handling for Content v2 has been removed. Use defineOgImage() in your page components instead.

// pages/[...slug].vue
defineOgImage({
  component: 'NuxtSeo',
  // ...
})

Config Changes

strictNuxtContentPaths Removed

This option was deprecated and has no effect in Nuxt Content v3. Remove it from your config:

export default defineNuxtConfig({
  ogImage: {
-   strictNuxtContentPaths: true,
  }
})

Chromium node Binding Removed

The deprecated chromium: 'node' compatibility option has been removed. Use 'playwright' instead:

export default defineNuxtConfig({
  ogImage: {
    compatibility: {
      runtime: {
-       chromium: 'node',
+       chromium: 'playwright',
      }
    }
  }
})

Import Path Changes

#nuxt-og-image-utils Alias Removed

If you were importing from this legacy alias, update your imports:

- import { ... } from '#nuxt-og-image-utils'
+ import { ... } from '#og-image/shared'

useOgImageRuntimeConfig Import Path

The deprecated stub export from #og-image/shared has been removed. Import from the correct path:

- import { useOgImageRuntimeConfig } from '#og-image/shared'
+ import { useOgImageRuntimeConfig } from '#og-image/app/utils'

URL Path Changes

Shorter Paths

OG Image URLs have been shortened:

v5v6
/__og-image__/image//_og/d/
/__og-image__/static//_og/s/
/__og-image__/font//_og/f/
/__og-image__/debug.json/_og/debug.json

New Cloudinary-style URL Encoding

Breaking: OG Image URLs now encode all options directly in the URL path using a Cloudinary/IPX-style format. This enables automatic CDN caching since the same options always produce the same URL.

v5 format:

/_og/d/satori/og.png?width=1200&title=Hello%20World

v6 format:

/_og/s/w_1200,title_Hello+World,p_Ii9zYXRvcmki.png

Key changes:

  • Options are comma-separated in the URL path (not query params)
  • Known params use short aliases: w (width), h (height), c (component), k (key), etc.
  • Component props are flattened to top level: title_Hello+World
  • Complex values (fonts, query params) are base64 encoded
  • Page path is encoded as p_<base64>

Hash Mode for Long URLs (Prerendered Only)

When prerendering, if the encoded URL path exceeds 200 characters (filesystem limit is 255), the module automatically switches to hash mode:

/_og/s/o_1whacq.png

This typically happens with:

  • Long component props (e.g., lengthy descriptions)
  • Multiple custom fonts with base64-encoded configurations
  • Complex query parameters

The hash is deterministic - the same options always produce the same hash. Options are cached by hash during prerendering for lookup when rendering the image. Hash mode URLs are not supported at runtime.

If you have any hardcoded references to the old URL format, update them to use getOgImagePath() instead:

import { getOgImagePath } from '#og-image/app/utils'

const ogImageUrl = getOgImagePath('/about', {
  props: { title: 'About Us' }
})

Community Templates Must Be Ejected

Community templates (like NuxtSeo, Brutalist, SimpleBlog, etc.) are no longer bundled with production builds. If you're using a community template, you must eject it before building:

# List available templates
npx nuxt-og-image list

# Eject a specific template
npx nuxt-og-image eject NuxtSeo

This copies the template to your components/OgImage/ directory where it will be included in your build.

In development, community templates continue to work without ejecting - they're loaded directly from the module.

In production, only ejected templates are available. If you reference a community template that hasn't been ejected, you'll get an error.

After ejecting, you can customize the template as needed. The ejected components are yours to modify.

Cache Key Changes

Query Parameters Excluded by Default

Query parameters are no longer included in cache keys. Previously, /page?foo=bar and /page?baz=qux would generate separate cached images. Now they share the same cache.

If your OG images depend on query parameters, enable them explicitly:

export default defineNuxtConfig({
  ogImage: {
    cacheQueryParams: true // restore v5 behavior
  }
})

Or set a custom cache key per image:

defineOgImage({
  cacheKey: `my-page-${route.query.variant}`
})

Cache Version Control

New cacheVersion option controls cache key namespacing:

export default defineNuxtConfig({
  ogImage: {
    // Default: module version (cache invalidates on upgrade)
    cacheVersion: false // disable versioning entirely
  }
})

Behavior Changes

Sharp JPEG Errors

Previously, if Sharp failed to load for JPEG rendering, it would log an error and fall back to PNG silently. Now it throws an error.

Ensure Sharp is properly installed and your runtime supports it if you're using JPEG output. See the Renderers guide for details.

Tailwind / CSS Changes

UnoCSS Runtime Removed

The UnoCSS runtime transformer that processed Tailwind/UnoCSS classes at runtime has been removed. Utility classes are now processed at build time with native Tailwind v4 support.

What this means:

  • @unocss/nuxt is no longer supported for OG image styling
  • Custom UnoCSS shortcuts in uno.config.ts won't work in OG components
  • Tailwind classes continue to work (with Tailwind v4 or @nuxtjs/tailwindcss)

Native Tailwind v4 Support

Nuxt OG Image now has native Tailwind v4 support. Classes are extracted from your OG components at build time and compiled with Tailwind's CSS engine.

If using @nuxtjs/tailwindcss:

No configuration needed - the module auto-detects your Tailwind setup.

If using Tailwind v4 with the Vite plugin:

Point the module to your CSS entry file:

nuxt.config.ts
export default defineNuxtConfig({
  ogImage: {
    tailwindCss: '~/assets/css/main.css'
  }
})

Your CSS file should include @import "tailwindcss" and any @theme customizations.

Theme Customizations

Custom theme values defined in @theme are automatically resolved:

assets/css/main.css
@import "tailwindcss";

@theme {
  --color-brand: #ff6600;
  --font-heading: "Inter", sans-serif;
}
components/OgImage/MyTemplate.satori.vue
<template>
  <div class="bg-brand font-heading">
    Works!
  </div>
</template>

Nuxt UI v3 Color Support

When using @nuxt/ui v3, semantic colors (primary, secondary, etc.) from your app.config.ts are automatically resolved:

app.config.ts
export default defineAppConfig({
  ui: {
    colors: {
      primary: 'indigo',
      secondary: 'violet'
    }
  }
})
components/OgImage/MyTemplate.satori.vue
<template>
  <div class="bg-primary-500 text-secondary-200">
    Nuxt UI colors!
  </div>
</template>
Did this page help you?