Product
Monday, September 15, 2025
Building a Dynamic Open Graph Image Generator with Satori and Next.js
- Sanjay Soundarajan@megasanjay
Stop manually designing Open Graph images. If you share blog posts, projects, or docs on Twitter, LinkedIn, or Slack, you know how important OG images are for engagement. They are the preview cards that make links stand out, grab attention, and reinforce your brand. If you care about how your work appears on social media, OG images aren’t just nice-to-have, they’re the difference between someone scrolling past and someone clicking through.
With a small team, design tasks often landed on whoever had time, which usually meant me. Every new post or docs page meant tweaking a layout, exporting a PNG, and uploading it. It quickly became a chore on top of development work.
That is why we built Kalai, a flexible, dynamic OG image generation service powered by Vercel’s Satori. It is the same service we use across all of our apps and services at Fair Data Innovations Hub. In this post I will walk you through how it works and how you can build your own.
Why Generate OG Images Dynamically?
Traditionally, OG images are either:
- Manually designed: looks nice, but impossible to keep up with
- Templated in design tools: semi-automated, but still requires exporting and uploading
- Headless browser screenshots: flexible, but slow and resource-hungry
We started in the first camp. I still remember designing the very first OG image for our SODA for SPARC page. At the time, we only had two projects, so it felt doable. But as the number of projects grew, I found myself spending more time in Figma than writing code.

Exporting a PNG from a design tool and uploading it every time you publish a post feels fine the first three times. By the tenth time, you start dreading it.
Dynamic generation with Satori offers a better way:
- Render JSX directly to SVG (and then to PNG)
- No Chrome or Playwright dependencies, which makes it work in serverless environments
- Flexible layouts using React components and CSS-like styling
- Fast enough to generate on the fly for each request
Meet Kalai
Kalai is our open source OG image generator. We built it with a few design goals in mind:
- Multi-tenant: handle OG images for multiple apps and organizations
- Consistent branding: centralized templates so all our projects share the same look
- Deploy anywhere: works great on Vercel with Next.js, but it is just an API so you can run it in Express, Deno, or any server that supports Node
The first time I hit a Kalai endpoint and saw a fresh OG image pop up in Slack, I grinned. It felt like magic, and instantly saved me from fiddling with templates.
Once deployed, any of our apps can simply point their <meta property="og:image" />
tag to a Kalai endpoint and it just works.
How It Works
At its core, Kalai is just an API route that:
- Reads query parameters (title, org, author, etc.)
- Passes them into a React component rendered by Satori
- Converts the SVG output to PNG using Resvg
- Returns it as a
Content-Type: image/png
response
Here is a minimal example using satori
directly with Next.js. This keeps the code short and easy to follow. In Kalai’s production setup we use @vercel/og, which builds on top of satori and makes it easier to integrate with Vercel.
// pages/api/og.ts
import satori from 'satori';
import { Resvg } from '@resvg/resvg-js';
export default async function handler(req, res) {
const { title = 'Hello World', org = 'MyOrg' } = req.query;
// Render JSX to SVG
const svg = await satori(
<div style={{ fontSize: 48, color: 'black', padding: '40px' }}>
<h1>{title}</h1>
<p>{org}</p>
</div>,
{
width: 1200,
height: 630,
fonts: [
{
name: 'Inter',
data: await fetch(
'https://og-playground.vercel.app/inter-latin-ext-700-normal.woff'
).then((res) => res.arrayBuffer()),
weight: 700,
style: 'normal',
},
],
}
);
// Convert SVG to PNG
const resvg = new Resvg(svg);
const png = resvg.render().asPng();
res.setHeader('Content-Type', 'image/png');
res.send(png);
}
👉 You can see the full production-ready version we use in Kalai here: pages/api/generate.tsx
With this in place, you can now hit:
`https://kalai.fairdataihub.org/api/generate?title=${encodeURIComponent('Hello from Kalai')}&description=${encodeURIComponent('This is a sample image generated just for you!')}&app=fairdataihub&org=fairdataihub`;
and get a freshly generated OG image.
Real-World Usage
At Fair Data Innovations Hub, we use Kalai across all of our projects. Since we don’t have a dedicated design team, developers, myself included, often end up wearing the designer hat too. That meant every blog post or docs page came with an extra mental load: “ugh, time to make another image.”
Kalai lifted that weight off our shoulders. Now, instead of bouncing between code and design tools, we can focus on building, and still get clean, branded previews for free.
- Blogs get OG images with the post title and author
- Apps get branded preview cards with app name and logo
- Services share a consistent design system
Because it is API-driven, we can roll it out to a new project in minutes. The result is clean, professional link previews everywhere without extra design overhead.
Documentation Sites
One of the places where Kalai really shines is in our documentation. We build user documentation for our apps with Docusaurus.
With Kalai, every docs page can have a relevant OG image automatically generated. This is especially useful since documentation links are often shared in platforms like Slack and Microsoft Teams, where the preview image can make the link more recognizable and inviting.
Instead of generic or missing previews, contributors and users now see branded images that match the specific docs page they are sharing.
As you can see, each of our apps has its own background design, and Kalai makes sure the OG image matches it. The use of Kalai in our documentation has been a game changer for us.
Alternatives
Satori works well if you are already using React and Vercel, but it is not the only option for dynamic OG image generation.
For example, Takumi is a Rust-based OG image generator that focuses on performance and flexibility. Rust solutions can be appealing if you want very fast image rendering or if your stack is not centered on Node.js.
The overall idea is the same: generate OG images dynamically instead of maintaining static files. The tools you choose depend on your stack, performance needs, and deployment environment.
Conclusion
Open Graph images are a small detail that make a big impact. With Satori, generating them dynamically is finally fast, flexible, and serverless-friendly.
If you want to try it out, check out Kalai on GitHub. Fork it, deploy it, and start giving your projects the polished social previews they deserve. We built Kalai to scratch our own itch, but it’s been a game changer for our workflow. I hope it saves you the same time (and headaches) it saved us.
⭐ If you find Kalai useful, consider giving the repository a star on GitHub, it helps others discover the project and supports continued development.
Acknowledgements
Some of the content for this post was made better with the help of ChatGPT's writing tools.