Generate Social Preview Images at the Edge
OpenGraph Images
An `opengraph-image.tsx` file in `app/` generates dynamic OG images using JSX rendered to a PNG via `ImageResponse`.
What you'll learn
- Add `opengraph-image.tsx`
- Use `ImageResponse` from `next/og`
- Combine with route params for per-page OG images
OG images are what social platforms show when someone shares your link. Generating them per page used to mean a headless browser; Next can do it with plain JSX rendered to a PNG on the Edge.
A Static OG Image
// app/opengraph-image.tsx
import { ImageResponse } from 'next/og'
export const runtime = 'edge'
export const size = { width: 1200, height: 630 }
export const contentType = 'image/png'
export default function Image() {
return new ImageResponse(
(
<div
style={{
fontSize: 80,
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
My Site
</div>
),
size,
)
} Drop this file anywhere in app/. Next discovers it, generates the PNG, and links it
from the matching page’s metadata automatically.
Per-Page OG With Params
// app/posts/[slug]/opengraph-image.tsx
import { ImageResponse } from 'next/og'
export const runtime = 'edge'
export const size = { width: 1200, height: 630 }
export default async function Image({ params }: { params: { slug: string } }) {
const post = await db.post.findUnique({ where: { slug: params.slug } })
return new ImageResponse(
(
<div style={{ fontSize: 60, padding: 80 }}>
{post?.title ?? 'Post'}
</div>
),
size,
)
} ImageResponse understands a subset of CSS — flexbox, gradients, custom fonts, images.
Twitter cards work the same way via a twitter-image.tsx sibling file.