A Next.js OG image has two good implementations, and they fail in different places. ImageResponse generates the image inside your app. A template API signs a URL and lets another service render it. Pick by who edits the layout and how complex it is, not by which demo looks nicer.
Option 1: opengraph-image and ImageResponse
Next.js supports an opengraph-image file convention and the ImageResponse constructor, which turns JSX and CSS into a PNG at 1200 by 630 by default. It runs inside your deployment with no extra service.
The documented limits matter: only flexbox and a subset of CSS properties work, display: grid will not, and the bundle, including fonts and images, is capped at 500KB. The layout lives in your repo, so a designer’s change is an engineer’s pull request.
Option 2: sign a URL from a template
import type { Metadata } from "next";
export async function generateMetadata({ params }): Promise<Metadata> {
const post = await getPost((await params).slug);
const { url } = await client.signImageUrl({
template: process.env.OG_TEMPLATE_ID!,
format: "png",
layers: { headline: { text: post.title } },
});
return {
openGraph: { images: [{ url, width: 1200, height: 630, alt: post.title }] },
};
}
generateMetadata renders the tag into the server HTML. The designer edits the template in the editor; your code only sends the title. The signed URL contains the pinned template version, so a design change never alters a card that is already live.
How to choose
| Question | ImageResponse | Template API |
|---|---|---|
| Is the layout simple text on a gradient? | Fits | Fits |
| Does it need grid, many fonts, or large images? | Hits the documented limits | Fits if the editor can draw it |
| Does a designer edit it? | Needs an engineer | Edits in the editor |
| Does it add a service dependency? | No | Yes |
| Is cost per image zero? | Compute only | One credit per unique URL |
The honest default
Start with ImageResponse if you have one layout, one engineer, and no designer in the loop. Move to a template when the second layout or the first design request arrives. The cutover is small: replace the opengraph-image file with the generateMetadata function above.
Implementation detail and WordPress are in Sign Open Graph Image URLs in Next.js and WordPress. The pipeline and debugging live in the Open Graph image generator guide.
FAQ
How do I generate a dynamic OG image in Next.js?
Use the opengraph-image file convention with ImageResponse to render JSX to a PNG in your app, or return a signed template-API URL from generateMetadata.
What are the limits of Next.js ImageResponse?
Next.js documents support for flexbox and a subset of CSS properties, no display: grid, and a 500KB bundle limit that includes fonts, images, and other assets.
Does jsontoimg replace ImageResponse?
It is an alternative. ImageResponse keeps the layout in code with no extra service. jsontoimg moves the layout into an editor so a designer can change it without a deploy.
What does a template API cost per OG image?
One credit for the first unique URL fetched, and zero for repeat fetches of the same title. Minting the signed URL is free.
Related Resources
- How JSON-to-image conversion works — the pillar guide
- Open Graph image generator guide — the full flow
- HTML to image API vs template API — the general trade-off
- Open Graph images use case — signed OG URLs