Generates images and short videos from templates through an API: you design once, then pass text and pictures and it returns a finished file.
Build me an image generation API that replaces Bannerbear: templates designed once, filled with text and pictures over HTTP, returned as finished files. STACK - Node 20+ with Fastify - SQLite through better-sqlite3, WAL mode - satori for layout and @resvg/resvg-js for rasterising, sharp for post-processing — no headless browser for images - ffmpeg only for the video templates - Caddy in front THE DATA MODEL - templates: id, uid, name, width, height, layers_json, fonts_json, version, created_at - template_versions: id, template_id, version, layers_json, created_at — a template is versioned, and a render records the version it used - renders: id, uid, template_id, template_version, payload_json, status, output_path, output_hash, width, height, bytes, ms, error, created_at - collections: id, uid, name, template_ids_json — one payload rendering the same content at several sizes - api_keys: id, name, hash, scopes_json, rate_per_minute, created_at, revoked_at - fonts: id, family, weight, style, file_path — self-hosted, never fetched at render time - assets: id, kind, path, sha256, width, height — uploaded images stored locally THE TEMPLATE - A template is a list of layers: text, image, shape, group. Each has a name, a box, and properties - Text layers: font family, weight, size, colour, alignment, line height, letter spacing, and a fitting mode — wrap, shrink to fit, or truncate with an ellipsis. Choose it per layer, because a headline and a byline fail differently - Auto-shrink must be a real binary search on the rendered height, not a character count. A name of forty characters in a box built for twenty is the case this product exists to handle - Image layers: fit, fill or stretch, with a focal point, corner radius and an optional colour overlay - Shape layers: rectangles with radii, lines, and a gradient fill - Layers can be hidden by the payload, and a hidden layer's space either collapses or is held, declared per group THE API - POST a render with the template uid and a flat object of layer names to values; get back a URL - Synchronous for simple templates under a deadline, asynchronous with a webhook otherwise, chosen by the caller - Idempotency: the same template version and the same payload returns the same file rather than rendering again, keyed on a hash of both. This alone removes most of the load - Signed GET renders too, so an image tag can be the whole integration - Errors name the layer and the reason: a missing font, an unfetchable image, text that could not fit even at the minimum size FONTS AND IMAGES, WHERE THIS BREAKS - Every font is uploaded and stored; nothing is fetched from a CDN at render time. A render that depends on the network is a render that fails at the worst moment - Subset check: if a payload contains glyphs the font does not have, say so rather than drawing empty boxes. Emoji and CJK need their own declared fallback font - Remote images are fetched once, hashed, stored, and re-used; the fetch has a timeout, a size cap and no redirects to private addresses - A missing image renders the layer's placeholder, and the render is marked degraded rather than failed — with the reason recorded THE EDITOR - A canvas with the layers listed beside it, drag to move, handles to resize, a properties panel - Snapping to edges, centres and to other layers, with alignment tools - A preview panel where you type sample values and watch it render for real, through the same code path as the API - Save creates a new version; old versions keep rendering, because a template edited on Tuesday must not change an image embedded in an email sent on Monday VIDEO, IF NEEDED - Short templates only: a still composition with timed text and a background clip or image, assembled by ffmpeg from rendered frames - Rendered by a worker, always asynchronous, with a hard duration cap - Say clearly that this is the expensive part and is worth skipping unless it is actually needed OPERATIONS - .env: DATABASE_PATH, STORAGE_PATH, BASE_URL, SIGNING_SECRET, MAX_CONCURRENCY - Migrations on boot, each once - A render queue with a concurrency cap, because rasterising is CPU-bound and unbounded parallelism is how the box falls over - Output files cached with immutable headers and a content hash in the name - Nightly backup of the database and templates; renders are reproducible and need not be backed up - Health endpoint that renders a one-layer template WHAT MATTERS MOST Text fitting and idempotency. Build the shrink-to-fit binary search and the payload-hash cache first, then throw a hundred real names, titles and prices at one template. A generator that clips a headline is a generator whose output cannot be published unread. Give me the repository, migrations, .env.example, three seed templates, and a README with deploy steps behind Caddy.
What you lose
- A visual template editor so a designer can change the layout without touching code
- Rendering capacity for bursts without you provisioning anything
- Video templates as well as images
If you would rather not build
- Playwright screenshotting an HTML template
- Sharp compositing, for simple layouts
What it costs
read from their page 15 Aug 2026
| Plan | Billed monthly | Billed yearly | Last read |
|---|---|---|---|
| — | $49/mo | — | 15 Aug 2026 |
Their pricing page is where these came from. Seeing a different price? Tell us.
The escape hatch
open source · no votes, no paid placement
Why this verdict
our own opinion · changed only by a person
89/100
Verdict yes at 89. satori plus resvg is the whole engine. The size ladder is the only piece of real craft.
History
tracked since 10 Aug 2026 · nothing is ever overwritten
Questions about Bannerbear
answered from the record above
Is Bannerbear free?
No — the plan we track is $49 a month. Automate at around $49/month billed monthly for a fixed number of generated images.
Can you replace Bannerbear by building your own?
YES. Replaceable in one session with an AI coding agent. Replacement score 89 out of 100, build time one session. Read what you lose before you decide.
How much does Bannerbear cost?
$49 a month on Automate — $588 a year. Recorded 10 Aug 2026.
What do you lose by replacing Bannerbear?
A visual template editor so a designer can change the layout without touching code; Rendering capacity for bursts without you provisioning anything; Video templates as well as images. If any of those carry weight for you, keep paying.
Is there an open-source alternative to Bannerbear?
Yes: satori, resvg-js. The prompt on this page is for when you want it your way instead.
Related entries
same category first, most replaced first
Every week, something stops being worth paying for.
New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.
free forever · no tracking pixel · stored here, never passed to anyone

