Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/vercel/next.js/llms.txt

Use this file to discover all available pages before exploring further.

ImageResponse lets you generate dynamic images using JSX and CSS. This is useful for social media images such as Open Graph images and Twitter cards.
import { ImageResponse } from 'next/og'

new ImageResponse(
  element: ReactElement,
  options?: ImageResponseOptions
)

Parameters

element
ReactElement
required
A React element (JSX) describing the image layout. Only a subset of CSS and HTML is supported.
options
ImageResponseOptions
Optional configuration:

Supported CSS

ImageResponse supports common CSS including:
  • Flexbox layout (display: flex)
  • Absolute positioning
  • Custom fonts
  • Text wrapping and centering
  • Nested images
Advanced layouts like CSS Grid (display: grid) are not supported. For a full list of supported properties, see Satori’s documentation.

Behavior

  • Uses @vercel/og, Satori, and Resvg to convert JSX/CSS into PNG.
  • Maximum bundle size is 500KB (includes JSX, CSS, fonts, images, and other assets).
  • Supported font formats: ttf, otf, woff. Prefer ttf or otf for faster parsing.

Examples

In a Route Handler

app/api/og/route.tsx
import { ImageResponse } from 'next/og'

export async function GET() {
  try {
    return new ImageResponse(
      (
        <div
          style={{
            height: '100%',
            width: '100%',
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'center',
            justifyContent: 'center',
            backgroundColor: 'white',
            padding: '40px',
          }}
        >
          <div style={{ fontSize: 60, fontWeight: 'bold' }}>
            Welcome to My Site
          </div>
        </div>
      ),
      { width: 1200, height: 630 }
    )
  } catch (e: unknown) {
    return new Response('Failed to generate image', { status: 500 })
  }
}

With opengraph-image.tsx

app/opengraph-image.tsx
import { ImageResponse } from 'next/og'

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

export default async function Image() {
  return new ImageResponse(
    (
      <div
        style={{
          fontSize: 128,
          background: 'white',
          width: '100%',
          height: '100%',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        My site
      </div>
    ),
    { ...size }
  )
}

With custom fonts

app/opengraph-image.tsx
import { ImageResponse } from 'next/og'
import { readFile } from 'node:fs/promises'
import { join } from 'node:path'

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

export default async function Image() {
  const interSemiBold = await readFile(
    join(process.cwd(), 'assets/Inter-SemiBold.ttf')
  )

  return new ImageResponse(
    (
      <div style={{ fontFamily: 'Inter', fontSize: 64, display: 'flex' }}>
        My site
      </div>
    ),
    {
      ...size,
      fonts: [
        {
          name: 'Inter',
          data: interSemiBold,
          style: 'normal',
          weight: 600,
        },
      ],
    }
  )
}

Version history

VersionChanges
v14.0.0ImageResponse moved from next/server to next/og.
v13.3.0ImageResponse importable from next/server.
v13.0.0ImageResponse introduced via @vercel/og.