Generating Open Graph images in Next.js from a React Component
01What is a generated Open Graph image?#
As you would expect, generated Open Graph Images in Next.js is a feature that allows users to generate a social image from a React component. This feature is really useful when doing a blog like this, as bad screenshots for the posts would just have been a waste of bytes and using AI generated images isn’t the way I wanted to go.

02How to generate Open Graph images in Next.js?#
Using Next.js ImageResponse Constructor in a special file used for file-based metadata you can generate an Open Graph image.
To make a generated Open Graph image, create a opengraph-image.tsx file and make the default export a function returning a new instance of the ImageResponse constructor.
import { ImageResponse } from "next/og";
export default function OpenGraphImage() {
return new ImageResponse(<p>I am a Opengraph Image</p>);
}03Dynamic content for the Open Graph Image#
In my case I needed custom Open Graph images for each posts, so I needed to fetch the meta data for each post. As with dynamic route segments in Next.js the current path or slug can be retrieved using by awaiting the params.
import { ImageResponse } from "next/og";
import { OgCard, ogFonts, ogSize } from "@/lib/og-image";
export default async function Image({ params }: PageProps<"/posts/[slug]">) {
const { slug } = await params;
const [post, settings] = await Promise.all([
client.fetch(POST_SEO_QUERY, { slug }),
client.fetch(SETTINGS_QUERY),
]);
if (!post || !settings) {
return new Response("Not found", { status: 404 });
}
const publishedAt = post.publishedAt ? isoDate(post.publishedAt) : null;
const tags = post.tags?.flatMap((tag) => (tag ? [`#${tag}`] : [])) ?? [];
const meta = [publishedAt, ...tags].filter(Boolean).join(" · ");
return new ImageResponse(
<OgCard
wordmark={settings.wordmark}
title={post.title}
meta={meta || undefined}
/>,
{ ...ogSize, fonts: ogFonts }
);
}04Putting it all together#
When styling the Open Graph image(s), the styles need to be inline and the fonts loaded. This is done within my OgCard components. Let us take a look at how do that in Next.js.
import { readFile } from "node:fs/promises";
import path from "node:path";
const BG = "#0e1014";
export const ogSize = { height: 630, width: 1200 };
export const ogContentType = "image/png";
const [newsreaderMedium, jetbrainsMonoRegular] = await Promise.all([
readFile(path.join(process.cwd(), "assets/fonts/Newsreader-Medium.ttf")),
readFile(path.join(process.cwd(), "assets/fonts/JetBrainsMono-Regular.ttf")),
]);
export const ogFonts = [
{
data: newsreaderMedium,
name: "Newsreader",
style: "normal" as const,
weight: 500 as const,
},
{
data: jetbrainsMonoRegular,
name: "JetBrains Mono",
style: "normal" as const,
weight: 400 as const,
},
];
interface OgCardProps {
wordmark: string;
title: string;
meta?: string;
}
export function OgCard({ wordmark, title, meta }: OgCardProps) {
return (
<div
style={{
background: BG,
display: "flex",
flexDirection: "column",
fontFamily: "Newsreader",
height: "100%",
justifyContent: "space-between",
padding: "64px 72px",
width: "100%",
}}
>
...
</div>
);
}Next.js is using satori for generating the Open Graph images, so please refer to the documentation for more information.
How to validate that a Open Graph image is rendered?
Either follow the path set on content on the og:image attribute in the dom or use an external tool. Search on Google for 'Open Graph Validator' or similar
What is Next.js using to render Open Graph images?
Next.js is using Satori to render the image used for Open Graph image
Why render an Open Graph image from a React component?
If you aren't able to produce an image for a list of articles, blogposts or similar and using AI is either not an option or wanted, producing an Open Graph image dynamically might be the solution
Get an email when a new post is published. Nothing more.