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-runThis will:
- Rename
components/OgImage/*.vueto include renderer suffix (defaults to.takumi.vue) - Migrate
defineOgImageComponent()calls todefineOgImage()
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/wasmSatori:
# Node.js
npm i satori @resvg/resvg-js
# Edge runtimes (Cloudflare, Vercel Edge, etc.)
npm i satori @resvg/resvg-wasmBrowser:
npm i playwright-coreRunning 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 rendererThis 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 v6Multiple 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').
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 NuxtSeoThis 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,
@themevalues 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:
@import "tailwindcss";
@theme {
--color-brand: #ff6600;
--font-heading: "Inter", sans-serif;
}<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:
export default defineAppConfig({
ui: {
colors: {
primary: 'indigo',
secondary: 'violet'
}
}
})<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:
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.
| v5 | v6 |
|---|---|
/__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%20Worldv6 format:
/_og/d/w_1200,title_Hello+World,p_Ii9zYXRvcmki.pngKey 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.pngThis 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.
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.vueConfiguration:
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:
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.