Index of every page on this site: llms.txt

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 (defaults to .takumi.vue)
  • Migrate defineOgImageComponent() calls to defineOgImage()

What's New

  • Takumi as recommended renderer - Takumi is 2-10x faster than Satori with the same feature set
  • First-class CSS support - Tailwind v4, UnoCSS, CSS variables, and Nuxt UI v3 colors all work
  • Redesigned DevTools - better debugging, Bluesky social card support, more accessible interface
  • Multiple OG images per page - different dimensions for different platforms
  • @nuxt/fonts integration - custom fonts work if you install @nuxt/fonts
  • Smarter caching - CDN-friendly Cloudinary-style URLs, cleaner cache keys

High Impact Changes

Changes that affect most users upgrading to v6.

Install Renderer Dependencies

Renderer dependencies (satori, resvg, takumi, playwright) are no longer bundled. You must install them explicitly based on your renderer and runtime.

See PR #415.

Takumi (recommended):

# Node.js
npm i @takumi-rs/core

# Edge runtimes
npm i @takumi-rs/wasm

Satori:

# Node.js
npm i satori @resvg/resvg-js

# Edge runtimes (Cloudflare, Vercel Edge, etc.)
npm i satori @resvg/resvg-wasm

Browser:

npm i playwright-core

Running nuxt dev in an interactive terminal asks before it installs a missing renderer dependency.

Non-interactive environments (AI coding agents, CI, or any process without a TTY) all behave the same way. The module never installs anything there. If a template needs a missing renderer, dev logs the install command (npx nypm add @takumi-rs/core) and a production build fails with the same command. If no template exists and no renderer is installed, the module logs npx nuxt-og-image enable takumi and keeps OG images off. Set NUXT_OG_IMAGE_SKIP_ONBOARDING=1 to opt out of onboarding entirely.

Component Renderer Suffix Required

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

See PR #433.

# 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.browser.vue  # for Browser 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    # Satori version
  MyTemplate.takumi.vue    # Takumi version (faster)

When calling defineOgImage('MyTemplate'), the module uses the first registered variant. To select a specific renderer, use dot notation ('MyTemplate.takumi') or PascalCase ('MyTemplateTakumi').

The module removed the defaults.renderer config option and renderer option on defineOgImage(). The component filename suffix always determines the renderer.

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.

See PR #426.

# 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.

Medium Impact Changes

Changes that affect users with specific configurations.

Fonts: @nuxt/fonts Integration

The module removed the ogImage.fonts config. @nuxt/fonts now handles fonts - install the module and your fonts work in OG images with no extra configuration.

See PR #432.

The module bundles Inter (400 and 700) as a zero-config fallback, so if you were only using Inter you can delete your font configuration entirely.

// Before
export default defineNuxtConfig({
  ogImage: {
-   fonts: ['Inter:400', 'Inter:700']
  }
})

// After (Inter only) — remove the config, it works by default

// After (custom fonts) — just install @nuxt/fonts
export default defineNuxtConfig({
+ modules: ['@nuxt/fonts', 'nuxt-og-image'],
+ fonts: {
+   families: [
+     { name: 'Roboto', weights: [400, 700], global: true }
+   ]
+ }
})

Install @nuxt/fonts:

npx nuxt module add @nuxt/fonts

<OgImage> and <OgImageScreenshot> Components Removed

The module removed the <OgImage> and <OgImageScreenshot> Vue components. Use the equivalent composables instead:

- <template>
-   <OgImage />
- </template>

+ <script setup>
+ defineOgImage('NuxtSeo.takumi')
+ </script>

defineOgImage() takes the component name as its first argument. <OgImage> rendered NuxtSeo when it named no component. NuxtSeo is a community template now, so eject it or pass your own template name.

- <template>
-   <OgImageScreenshot />
- </template>

+ <script setup>
+ defineOgImageScreenshot()
+ </script>

The migration CLI replaces each component with a comment that holds the matching composable call. Move that call into <script setup>.

componentOptions Config Removed

The module removed the ogImage.componentOptions config option since there are no longer any components to configure.

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

Object Syntax with url Replaced by useSeoMeta

The defineOgImage() object syntax for pre-prepared images is no longer needed. Use useSeoMeta() directly instead - it works without any interference from the module.

- defineOgImage({ url: '/my-image.png', width: 1200, height: 600, alt: 'My Image' })
+ useSeoMeta({ ogImage: '/my-image.png', ogImageWidth: 1200, ogImageHeight: 600, ogImageAlt: 'My Image' })

The migration CLI handles this automatically.

defineOgImageComponent Deprecated

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

See PR #433.

- defineOgImageComponent('NuxtSeo', { title: 'Hello' })
+ defineOgImage('NuxtSeo', { title: 'Hello' })

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

First-Class CSS Support

Build-time CSS processing replaces the UnoCSS runtime transformer. Tailwind v4, UnoCSS, CSS variables, and Nuxt UI v3 colors all work by default with zero configuration.

See PR #430.

What this means:

  • Tailwind v4 - build-time class extraction with Tailwind's CSS engine, @theme values work
  • UnoCSS - full UnoCSS support
  • CSS Variables - use your app's CSS custom properties directly in OG image templates
  • Nuxt UI v3 - the module automatically resolves semantic colors (primary, secondary, etc.)

Native Tailwind v4 Support

Nuxt OG Image has native Tailwind v4 support. The module extracts classes from your OG components at build time and compiles them with Tailwind's CSS engine. Zero-config - the module auto-detects your Tailwind setup whether you're using @nuxtjs/tailwindcss or Tailwind v4 with the Vite plugin.

Theme Customizations

The module automatically resolves custom theme values defined in @theme:

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, the module automatically resolves semantic colors (primary, secondary, etc.) from your app.config.ts:

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>

Low Impact Changes

Changes that affect users with specific edge cases or deprecated configurations.

Cache Key Changes

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.

See PR #427.

The URL path encodes all image options, so query parameters on the OG image URL have no effect. In v5, query parameter overrides (e.g. ?title=Override) worked in production without URL signing. In v6, query param overrides only work in dev and prerender modes. Use defineOgImage props to pass dynamic values instead.

Cache Version Control

New cacheVersion option controls cache key namespacing:

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

URL Path Changes

OG Image URLs have been shortened and restructured. This only affects you if you have hardcoded OG image URLs.

See PR #305.

v5v6
/__og-image__/image//_og/d/
/__og-image__/static//_og/s/
/__og-image__/font/Removed (fonts served directly from /_fonts/ via @nuxt/fonts)
/__og-image__/debug.json/_og/debug.json

New Cloudinary-style URL Encoding

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/d/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
  • The module encodes the page path as p_<base64>

Hash Mode for Long URLs (Prerendered Only)

When prerendering, the module switches to hash mode in two cases. The first is an encoded path over 200 characters; the filesystem limit is 255. The second is a path that holds a character outside A-Z a-z 0-9 _ . ~ -, such as a comma or a plus sign. Some static hosts redirect those paths, and social crawlers often do not follow the redirect.

/_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. The module caches options 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 the return value of defineOgImage() which now returns an array of generated paths:

const [ogImageUrl] = defineOgImage('NuxtSeo.takumi', { title: 'About Us' })

Long Runtime URLs

Because all options are now self-contained in the URL, runtime URLs can become long when passing many props. In v5, the URL was short because the server re-fetched the page to discover the payload - v6 avoids this round trip for stability and caching, at the cost of longer URLs.

See the Performance guide for strategies to reduce URL size, optimize component rendering, and configure caching for production.

Nuxt Content v2 Support Removed

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

See PR #410.

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

// pages/[...slug].vue
defineOgImage('NuxtSeo.takumi', { title: 'My Page' })

strictNuxtContentPaths Removed

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

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

Chromium Renderer Renamed to Browser

The chromium renderer has been renamed to browser for clarity. Update your component suffixes and configuration:

Component files:

# Rename component files
mv MyTemplate.chromium.vue MyTemplate.browser.vue

Configuration:

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

Browser node Binding Removed

The module removed the deprecated browser: 'node' compatibility option. Use 'playwright' instead:

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

Cloudflare Browser Rendering Support

You can now use Cloudflare Browser Rendering for runtime screenshots on Cloudflare Workers/Pages:

nuxt.config.ts
export default defineNuxtConfig({
  ogImage: {
    browser: {
      provider: 'cloudflare',
      binding: 'BROWSER'
    }
  }
})

See the Browser Renderer docs for setup instructions.

#nuxt-og-image-utils Alias Removed

See PR #410. 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 module removed the deprecated stub export from #og-image/shared. Import from the correct path:

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

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.

See PR #410.

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

Was this page helpful?