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.

working

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 }],
    }
  );
}