When someone shares your URL on Twitter, Slack, or LinkedIn, the preview card is your first impression. A branded OG image gets 2–5x more clicks than a generic one. Here's how to set them up in Next.js.
The approach: ImageResponse
Next.js provides ImageResponse from next/og — an edge-runtime function that renders JSX to a PNG image. Create an opengraph-image.tsx file in any route folder and export a default function that returns an ImageResponse.
Basic pattern
At minimum, your OG image needs: your brand mark, the page title, a subtitle, and a branded footer. Use a dark gradient background, white text, and your brand's accent color for visual pop.
Dynamic per-route images
For dynamic routes like /blog/[slug], accept params in the function and fetch the page data. Render the post title, category, and reading time on the card. Each URL gets its own unique preview.
The shared renderer pattern
Extract the OG image layout into a shared function in lib/seo/og-image.tsx. Each route's opengraph-image.tsx calls the shared function with route-specific data (eyebrow, title, subtitle, footer tags). One layout, many variants.
Design tips for OG images
- Brand mark top-left. Logo + wordmark at 32px. Establishes identity instantly.
- Title at 76–84px. Must be readable in a small preview thumbnail. Short, bold, high-contrast.
- Subtitle at 28px. One sentence of context. Muted color (70% opacity white on dark).
- Footer badges. Three to four keywords or tags at the bottom. Gives context without cluttering.
- Dark background gradient. Dark OG images stand out in light-mode feeds (which is most feeds).
Testing
Always test before shipping:
- Facebook Debugger — scrapes the URL and shows the resolved OG image.
- Twitter Card Validator — preview how the card renders on Twitter/X.
- LinkedIn Post Inspector — LinkedIn caches aggressively; use the inspector to force a refresh.
- Slack — paste the URL in a DM to yourself. Slack renders the preview inline.
Common mistakes
- Relative URLs. OG images must be absolute. Set
metadataBasein your root layout. - Missing on production. Edge-runtime OG images work differently in dev vs production. Always verify on the deployed URL.
- Too much text. The image renders at ~600px wide in most feeds. If you can't read it at that size, simplify.