Migrate from Bannerbear: The Actual Code Diff
To migrate from Bannerbear you do two things: rebuild the template as a design, and delete the code that waits for a callback. The first is manual and there's no way around it. The second is why most teams find the integration gets shorter rather than longer.
This isn't the post that argues you should switch. Bannerbear vs Imejis does that, honestly, including where they win. This one assumes you've decided and want to know what the work actually is.
What has to change and what doesntWhat has to change, and what doesn't
| Piece | Effort | Notes |
|---|---|---|
| Templates | Manual rebuild | No import path exists. This is the real cost |
| Auth header | Trivial | Authorization: Bearer becomes dma-api-key |
| The render call | Small | One request instead of create-then-wait |
| Webhook handler | Deleted | Nothing calls you back any more |
| Job polling or queue | Deleted | There's no job to poll |
| Image storage | Unchanged, or simpler | You already have the bytes; hosted delivery can also hold them |
Two of those rows are deletions, which is unusual for a migration and is the honest reason this one tends to go quickly.
The call goes from two steps to oneThe call goes from two steps to one
Bannerbear's model is asynchronous: you post the modifications, get a job back, and the finished image arrives later at a URL you registered. That's a reasonable design and it's why the handler exists.
The replacement is one request that answers with the image:
curl -X POST 'https://render.imejis.io/v1/YOUR_DESIGN_ID' \
-H 'dma-api-key: YOUR_KEY' \
-H 'Content-Type: application/json' \
-d '{
"headline": { "text": "Q3 results are in" },
"avatar": { "image": "https://cdn.example.com/u/812.jpg" }
}' \
--output card.pngIn Node, the whole integration is the request:
const res = await fetch(`https://render.imejis.io/v1/${designId}`, {
method: "POST",
headers: {
"dma-api-key": process.env.IMEJIS_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ headline: { text: title } }),
})
const image = Buffer.from(await res.arrayBuffer())Note the shape of the payload. Bannerbear addresses layers by name in a modifications array; here each layer is a key in the object, and the properties you send are the ones you marked dynamic on that layer. Everything not marked dynamic stays baked into the design, which is the safety rail against a caller sending something ugly.
Deleting the handler is the pointDeleting the handler is the point
The code that disappears is usually more than the code that changes:
- The webhook route, its signature verification, and its error paths.
- Whatever correlates a returning job id back to the record that asked for it.
- The queue or table row tracking in-flight renders.
- The retry logic for callbacks that never arrived.
- The local tunnel every developer needed to test any of it.
That last one is worth calling out. Testing an async image pipeline locally means exposing a public URL to your laptop. A synchronous call is testable from a terminal. That changes how quickly anyone on the team can pick the work up.
The trade-off is real and worth stating: a synchronous call holds a connection for the render duration. That's typically under 2 seconds, which is fine inside a request handler for most workloads, but if you're generating hundreds of images in a burst you'll want a worker doing it in parallel rather than a loop in a web request.
What doesnt portWhat doesn't port
Video. Bannerbear generates video; we don't, at all. If any part of your pipeline renders clips, that part has no equivalent here and this migration doesn't cover it. Creatomate is the usual destination for that job.
Your templates. There's no importer. Every template is a design you rebuild by hand. For three templates that's an afternoon. For eighty it's a project, and the sensible version is rebuilding the ones that carry real volume and leaving the long tail where it is until it's worth moving.
Their track record. Bannerbear has been at this longer, has more third-party tutorials, and has case studies we can't match. Their developer docs are genuinely good and their reliability is proven. None of that is a reason to stay if the price and the architecture suit you better, but pretending it isn't true would be silly.
What it costs to migrate from bannerbearWhat it costs to migrate from Bannerbear
Imejis pricing is as of September 2026, verified against our own billing config. Bannerbear's list price is as of August 2026 and is worth re-checking on their pricing page before you decide.
| Bannerbear entry | Imejis Basic | |
|---|---|---|
| Monthly | $49 | $14.99 |
| Free tier | 30 API calls, one-time | 100 renders a month, free, forever |
| Response | Async, webhook | Image in the response |
$49 against $14.99 is about 70% less. The free tier difference matters more than it looks during a migration specifically: you can rebuild and test templates against a permanent allowance rather than burning a one-time trial before you've finished porting.
When staying put is the right callWhen staying put is the right call
Say this to yourself honestly before starting:
- You render video. Stop here. This isn't a migration, it's a partial one, and partial migrations across two vendors cost more than either.
- You have a large template library and no volume problem. If the bill isn't hurting, rebuilding eighty templates buys you very little.
- Your team values the ecosystem. More tutorials, more Stack Overflow answers, a longer history. That's a real asset for a team that isn't deep in this problem.
- The async model is load-bearing for you. Some architectures genuinely want fire-and-forget. If yours does, a synchronous API is a step sideways.
Migrate one template firstMigrate one template first
Don't do a big bang. The path that works:
- Rebuild your highest-volume template as a design and mark the same fields dynamic.
- Render it with real production data and diff the output against the Bannerbear version by eye.
- Move that one call site, behind a flag if you have one.
- Watch it for a week, then work down the list by volume.
The API docs have tested calls in 33 languages and frameworks, and dynamic fields covers marking properties, which is the one concept that differs meaningfully from how Bannerbear modifications work.