ogrender vs Vercel OG
Vercel OG (@vercel/og) is free and good for a lot of cases. Here's exactly where it stops, and where it's still the right choice.
What Vercel OG actually is
@vercel/og uses Satori, a layout engine Vercel built specifically for generating images from JSX/HTML, running in an Edge function. It doesn't run a browser. It reimplements a subset of CSS layout in JavaScript, which is what makes it fast and free at the edge, and also what limits it.
| Vercel OG (Satori) | ogrender | |
|---|---|---|
| Rendering engine | Custom layout engine (Satori) | Real headless Chromium |
| CSS Grid | Not supported | Full support |
| Flexbox | Supported (its core layout mode) | Full support |
| Gradients, filters, box-shadow | Partial, many values silently ignored | Full support |
| Web fonts | Manual: fetch the font file yourself, pass it as an ArrayBuffer | Google Fonts via @import/<link>, no manual fetching |
| Emoji | Needs a Twemoji workaround; no native color emoji | Native color emoji, Noto fonts installed |
| Where it runs | Vercel Edge Runtime, inside a Next.js (or compatible) app | Any stack, over HTTP |
| Cost | Free, within your Vercel function limits | $6-39/month, flat |
Stay on Vercel OG if...
- You're already deployed on Vercel and your card layout is simple flexbox: a title, maybe an avatar and a footer row.
- You don't need CSS Grid, real gradients, or pixel-exact parity with your site's actual stylesheet.
- Free matters more than convenience, and you don't mind fetching and subsetting your own font files.
Switch when...
- Your card layout needs Grid. Satori doesn't support it, full stop, so any Grid-based design has to be rebuilt in flexbox first.
- You're not on Vercel, or you want the same render call from a Rails app, a cron job, or a static site generator's build step.
- You want to reuse your site's real CSS instead of hand-porting styles into Satori's supported subset.
- Color emoji and arbitrary web fonts matter and you don't want to maintain the Twemoji/font-fetching workarounds yourself.
Both approaches produce a PNG from markup. The difference is what CSS you're allowed to write to get there:
see the full parameter list in the docs.