The imageimageresponse & route handlers
I’ll need to design a card for every page.
You’ll design one. ImageResponse turns JSX — the same markup your components are made of — into a PNG the moment a request asks, and it is a route handler like any other: query in, image out. One file draws the card for every page you will ever publish.
Type a title and the server draws it. The same endpoint drew the link preview for this page — paste the URL into Slack and check us against it.
GET /api/og?title=The%20unofficial%20live%20playground%20for%20Next.js%20%26%20Vercel
asking the server for a PNG…
og.png · 1200 × 630open the file ↗
JSX → Satori (flexbox only) → PNG · rendered per request, cached by nobody
app/api/og/route.tsx
// app/api/og/route.tsx — a PNG factory disguised as a route
import { ImageResponse } from "next/og";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const title = clampTitle(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 }],
}
);
}