ogmake vs @vercel/og
@vercel/og and the Satori engine underneath it are free, open source (Satori is MIT-licensed), and genuinely
excellent. If you're already on Next.js (or another framework with an edge/serverless JS
runtime), rendering your OG image in-process with ImageResponse
is the right choice: no external service, no extra request, no account to manage. We are not
going to pretend otherwise — this page is about where that approach runs out, not about
whether it's good.
Where Satori's CSS runs out
Checked against Satori's own README, 2026-09-20.
| Limit | What it means |
|---|---|
| display: grid | Not supported. Satori's layout engine is Flexbox-only (the same engine React Native uses) — a design built around CSS Grid has to be rebuilt in nested flex containers. |
| z-index | Not supported — SVG (Satori's output format) has no z-index concept. Paint order is document order: an element you want on top has to come later in the markup, which can force restructuring a layout that relied on stacking. |
| Mixed fonts/weights in one text node | A bold word inside an otherwise-regular sentence needs a separate element with its
own fontFamily/fontWeight —
you can't vary styling inline within a single text node the way a browser renders
<b> inside a paragraph. |
CJK and emoji
Satori ships no fonts and does no system-font fallback — you supply every font as raw bytes
(ArrayBuffer/Buffer) via its options.
For CJK text that means bundling (or fetching at build/request time) a CJK-covering font
yourself and wiring it up per lang; Satori documents that "same
characters can be rendered differently in different locales" and that its Unicode
bidirectional layout support is incomplete, so mixed LTR/RTL text may not order the way a
browser would. Emoji are not drawn from a font at all by default — Satori renders them via a
graphemeImages/loadAdditionalAsset
callback you implement, mapping each grapheme to an image. It works, but it's a rendering
pipeline you build and maintain, not something that comes free with the package.
ogmake's own templates embed Latin-subset fonts only, so this isn't a solved problem on our side either — pick whichever engine you're using, you still need to supply CJK coverage yourself for non-Latin text.
No JS runtime at all
@vercel/og needs a JavaScript (edge or Node) runtime to execute — it's a library you call
from your app's own server code. If your stack has no JS runtime in the request path at
all — a Laravel or Django app, a static site with no server, a Go or Rust backend — using it
means standing up a separate Node service just to render images, which is real
infrastructure for what should be one HTTP call. A signed GET /i/{keyId}/{sig}
URL from ogmake works the same way from any language: see the Laravel and Django guides.
Where each is the right pick
| Situation | Pick |
|---|---|
| Next.js app, simple flex layout, Latin text, willing to own font/emoji setup | @vercel/og — free, in-process, no external dependency. |
| Non-JS stack (Laravel, Django, Rails, plain HTML), or a layout Satori's CSS subset can't express | ogmake — one signed URL, any language, fonts already wired up (Latin subset; CJK still needs its own font either way). |
See Quickstart to try it, or the pricing page for cost.