The imageimageresponse & route handlers
One file can draw every social card you’ll ever need.
Every page you have published, and every page you have not written yet. ImageResponse turns JSX, the same markup your components are made of, into a PNG at the moment a request asks for it. It runs in a Route Handler like any other: query in, image out.
Pick a page and the server draws its card. The same route drew the link preview for this page. Paste this page’s URL into Slack and compare.
GET /api/og?title=The%20unofficial%20live%20playground%20for%20Next.js%20%26%20Vercel
rendering on the server…
og.png · 1200 × 630open the file ↗
one Route Handler · JSX in, PNG out · drawn per request, flexbox only
app/api/og/route.tsx
// app/api/og/route.tsx — the Route Handler that draws the card
import { ImageResponse } from "next/og";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
// one of the site's own page titles, or the site line
const title = resolveTitle(searchParams.get("title"));
const fonts = await loadFonts(); // real .ttf files, read once
return new ImageResponse(
<div style={{ display: "flex", backgroundColor: "#071e26" }}>
{title}
</div>,
{
width: 1200,
height: 630,
fonts: [{ name: "JetBrains Mono", data: fonts.bold, weight: 700 }],
}
);
}