Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

To add an Open Graph (OG) image in a Next.js App Router project, place an opengraph-image.jpg, .jpeg, .png, or .gif file in the route segment that should own it. For route-specific or data-driven artwork, create an opengraph-image.tsx (or .js) file that returns an ImageResponse from next/og. Next.js then emits the corresponding og:image metadata automatically. The practical choice is simple: use a static file for authored, stable artwork; use a generated route when the title, author, price, or other page data must appear in the image.

This guide covers the App Router conventions documented for Next.js 16 (documentation updated February 27, 2026), including the promise-based image parameters introduced in that release.

How do I add an OG image in Next.js?

Next.js maps an image file convention to the route segment containing the file. A file in app/opengraph-image.png can serve as the site default, while app/blog/opengraph-image.jpg applies to the blog segment. A still deeper file wins over an ancestor image, so a route can override the site default without changing every page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The metadata-file reference lists JPG/JPEG, PNG, and GIF for static Open Graph images. The maximum static OG file size is 8 MB; exceeding it causes the build to fail. The 1200 × 630 pixel dimensions shown in the current documentation are a useful design target and documented example, not a universal requirement imposed by every social network. See the official opengraph-image reference.

Static file procedure

  1. Create or open the App Router segment, such as app/, app/blog/, or app/blog/[slug]/.
  2. Add opengraph-image.jpg, opengraph-image.jpeg, opengraph-image.png, or opengraph-image.gif to that directory.
  3. Keep the file at or below 8 MB. Confirm that the artwork remains legible when displayed as a small social-card thumbnail.
  4. Build or run the application and inspect the page source for an og:image tag. Next.js supplies the image type, width, and height metadata when it can read those values from the file.

An optional sibling text file named opengraph-image.alt.txt supplies alternative text for the image. This is useful for metadata consumers that expose a description, although it does not replace meaningful text in the page itself.

Default image with route overrides

For a common pattern, put a general image at app/opengraph-image.png, then add a more specific file such as app/products/opengraph-image.jpg. Product pages under that segment use the product image; unrelated pages inherit the default. The App Router getting-started guide demonstrates this ancestor/descendant precedence: Metadata and OG images.

How do I generate a dynamic OG image in Next.js?

Create an opengraph-image.tsx, .ts, or .js route file and return an ImageResponse. The current documentation calls ImageResponse from next/og the easiest way to generate an image. It converts a JSX-like element and supported CSS through the @vercel/og, Satori, and Resvg pipeline into a PNG. A generated route can read route parameters and external data, making it suitable for article titles, user names, inventory values, or other page-specific content.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Working generated route for a static segment

Place this file at app/blog/opengraph-image.tsx:

import { ImageResponse } from 'next/og'

export const alt = 'A blog article preview'
export const size = { width: 1200, height: 630 }
export const contentType = 'image/png'

export default function Image() {
  return new ImageResponse(
    <div
      style={{
        background: '#111827',
        color: 'white',
        width: '100%',
        height: '100%',
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        padding: '80px',
        fontSize: 64,
      }}
    >
      Your blog title
    </div>
  )
}

The separate alt, size, and contentType exports describe the generated asset to Next.js. The example uses 1200 × 630 and image/png, matching the current reference example. Verify available options against the Next.js version installed in your project; the API reference currently available for ImageResponse is the version 15 page at nextjs.org/docs/15/app/api-reference/functions/image-response.

Route parameters in Next.js 16

For app/blog/[slug]/opengraph-image.tsx, current documentation types params as a promise. Await it before loading route-specific content:

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option
import { ImageResponse } from 'next/og'

type Props = {
  params: Promise<{ slug: string }>
}

export const size = { width: 1200, height: 630 }
export const contentType = 'image/png'

export default async function Image({ params }: Props) {
  const { slug } = await params
  const post = await getPost(slug)

  return new ImageResponse(
    <div
      style={{
        width: '100%',
        height: '100%',
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        background: 'white',
        color: 'black',
        padding: '72px',
      }}
    >
      <div style={{ fontSize: 30 }}>{post.category}</div>
      <div style={{ fontSize:  sixty }}>{post.title}</div>
    </div>
  )
}

async function getPost(slug: string) {
  // Replace with your database or CMS request.
  return { category: 'Engineering', title: slug }
}

Replace the accidental placeholder value in a real implementation with a number (for example, 60):

<div style={{ fontSize: 60 }}>{post.title}</div>

Next.js 16 changed both the params passed to image generation and the id passed by generateImageMetadata to promises. If an older project gives you a plain object, follow that installed release’s types rather than copying a newer signature blindly.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

CSS and rendering limits

ImageResponse supports flexbox and only a subset of CSS. Advanced layouts such as CSS Grid do not work in the documented renderer. Prefer nested flex containers, explicit dimensions, simple colors, borders, and spacing. Test long titles, missing data, and non-Latin text because a layout that looks correct for one string can overflow when content changes. External fonts and images must be made available to the renderer in a way supported by your deployed environment; do not assume browser-only APIs are present.

Choosing static versus generated images

Decision factor Static file Generated route
Content One authored design reused by a segment Unique title, author, price, or other data per route
Maintenance Edit an image asset Edit code and its data/template inputs
Data access No data lookup Can use route params and external data
Layout freedom Any design your image editor can export Only ImageResponse’s supported HTML/CSS subset
Failure risk Oversized or unsupported file can fail the build Runtime data, fonts, or unsupported CSS can break rendering
Output behavior File is evaluated as metadata for the segment Route is optimized and cached by default unless dynamic APIs, uncached data, or route configuration change that behavior

There is no documented performance benchmark that makes one approach universally faster. Choose static when the image does not need page data. Choose generated when personalization or automation is worth the additional rendering and data dependencies.

Adding explicit metadata instead of the file convention

The file convention is usually the least error-prone option, but you can also return image metadata from a page’s metadata or generateMetadata export. The openGraph.images field accepts image URLs and can include dimensions and alt text:

import type { Metadata } from 'next'

export const metadata: Metadata = {
  openGraph: {
    images: [
      {
        url: 'https://example.com/social-card.png',
        width: 1200,
        height: 630,
        alt: 'Example social card',
      },
    ],
  },
}

Use explicit metadata when the image is hosted elsewhere or when metadata is assembled alongside other page values. The metadata and generateMetadata APIs are supported only in Server Components; see the current generateMetadata reference. Avoid defining competing values accidentally: decide whether the segment’s convention file or explicit metadata should be authoritative.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Generating multiple OG variants with generateImageMetadata

When one segment needs several image variants, export generateImageMetadata. Each returned object requires an id; alt, size, and contentType are optional. The id is supplied to the image-generating function. The API was introduced in v13.3, and the current version history records the Next.js 16 promise change.

import { ImageResponse } from 'next/og'

export async function generateImageMetadata() {
  return [
    { id: 'light', alt: 'Light social card' },
    { id: 'dark', alt: 'Dark social card' },
  ]
}

export default async function Image({
  id,
}: {
  id: Promise<string>
}) {
  const variant = await id
  const background = variant === 'dark' ? '#111827' : '#f9fafb'
  const color = variant === 'dark' ? 'white' : '#111827'

  return new ImageResponse(
    <div style={{ display: 'flex', width: '100%', height: '100%', background, color }}>
      {variant} variant
    </div>
  )
}

Check the generateImageMetadata reference for the exact signature used by your installed release.

Metadata, caching, and deployment checks

  • Inspect generated HTML: confirm the final page contains an absolute og:image URL, not a development-only path.
  • Check response headers and status: a generated route must return an image response, not an exception page or HTML error.
  • Account for caching: generated metadata routes are statically optimized and cached by default. Dynamic APIs, uncached fetches, or route configuration can opt the route into different behavior. If an image must change immediately after a database update, review the caching rules for that data request and your installed Next.js release.
  • Keep files within limits: static OG images have an 8 MB limit. A twitter-image file has a separate documented 5 MB limit; do not apply that number to Open Graph files.
  • Test production: social crawlers may request the image without your browser session, so verify authentication, redirects, cookies, and host allowlists do not block it.

Troubleshooting common failures

The build fails with an oversized image

Cause: the static file exceeds 8 MB. Re-export at a lower quality, reduce dimensions, remove unnecessary metadata, or switch to a generated route. Confirm the resulting file size before rebuilding.

The image route returns an error

Cause: unsupported CSS, a browser-only API, an unhandled data error, or a malformed JSX tree. Start with a plain flexbox container and hard-coded text, then add data and styling one piece at a time. Check server logs for the first thrown exception.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers

A dynamic title is missing

Cause: the route parameter was not awaited in a Next.js 16-style generator, or the data lookup returned no record. Type params and id as promises where the current docs require it, await them, and render a safe fallback for missing content.

Grid or familiar browser CSS does not render

Cause: ImageResponse implements a restricted CSS subset. Replace Grid, complex positioning, filters, and unsupported features with nested flex containers and explicit sizes.

The social platform shows an old card

Cause: the platform or an intermediary cached the image. Confirm the URL and response first, then use that platform’s documented card refresh mechanism. If your own route is cached, review static optimization and data-cache configuration rather than adding random delays.

Metadata exists but no preview appears

Cause: an inaccessible or relative URL, a redirect the crawler cannot follow, robots or authentication blocking the request, or invalid image bytes. Use an absolute public URL, fetch it without a logged-in browser, and verify the content type matches the generated output.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Previewing and validating the rendered page

You can validate the final page with browser developer tools or a crawler-friendly HTTP request. For repeatable checks across many URLs, ScreenshotNeo can capture the rendered page or an image preview. ScreenshotNeo is a website screenshot API and MCP server; its clean-shot pipeline accepts consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture. Only clean shots are billed, while bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are reported and cost nothing.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

Call ScreenshotNeo after deploying your page to inspect the OG presentation:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Replace the example URL with your page URL. The same endpoint supports PNG, JPEG, WebP, and PDF output; its response includes X-Page-Verdict and X-Billed headers so you can tell whether a clean shot was produced and billed. Documentation and the full option list are at ScreenshotNeo docs.

ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. It supports full-page capture, device presets, custom viewport and retina scale, waiting for selectors or network idle, custom CSS and JavaScript, hidden selectors, cookies and headers, request blocking, caching TTLs, signed links, webhooks, bulk capture, and usage reporting.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots; every feature is included on every plan. Create a free ScreenshotNeo account.

Practical launch checklist

  • Choose a static file or generator based on whether each route needs unique data.
  • Use a 1200 × 630 design as the documented example, while checking the requirements of the platforms your audience uses.
  • Keep static files below 8 MB and use one of the documented extensions.
  • Export size, contentType, and alt for generated routes when appropriate.
  • Use flexbox and supported CSS only in ImageResponse.
  • Await Next.js 16 params and variant id promises.
  • Test production URLs without authentication and inspect the emitted metadata.
  • Review caching when image content depends on changing external data.

Frequently Asked Questions

Can I use an SVG as an opengraph-image file?

The current static file convention lists JPG, JPEG, PNG, and GIF. Use one of those formats or return a supported generated response instead.

Does an OG image replace the page title or description?

No. It supplies the social image. Define the page’s title and description separately through metadata or generateMetadata.

Where should a shared default image live?

Place it in the highest App Router segment that should inherit it, commonly app/opengraph-image.png, then add files in deeper segments when those routes need overrides.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why should I verify my installed Next.js version?

The current documentation records Next.js 16 promise-based params and variant ids, while API references can differ by release. Your project’s installed version determines the exact types and caching behavior.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.