Self-Hosted OG Image API in Pure Rust: No Chromium, 150ms Per Render
Browser-based screenshot pipelines and subscription APIs are not the only way to generate social cards. Cosy renders OG images from SVG templates and JSON in 150 ms per render, from a 13 MB Rust binary with no browser runtime.
Every blog post needs a social card. Every changelog entry, every release banner, every quote graphic. At some point, making them by hand stops scaling, and you start looking for an image generation API you can run yourself.
Search for a self-hosted option and the results are thin. You find subscription SaaS that renders on someone else's servers, or DIY recipes that wrap headless Chromium in Docker and call it done. A browser runtime is a heavy thing to keep alive for drawing rectangles and text.
There is a third path. Cosy is a template-based image renderer written in pure Rust. One 13 MB binary, no browser, no Node runtime. It takes an SVG template and a JSON file and returns a PNG. We measured 150 ms per render on our build server, cold process start included.
Why the usual options fight back
The SaaS route works, until it doesn't. Cloud template APIs like Bannerbear advertise seconds per render, price per image, and rate limits. Your cards render on infrastructure you don't control, your templates live in someone else's dashboard, and the bill scales with your publishing cadence, not with your server capacity.
The DIY route usually means a screenshot pipeline. Puppeteer or Playwright drives a headless Chrome download that weighs hundreds of megabytes, boots slowly, and breaks in creative ways when fonts or GPU flags shift between hosts. For output that is ultimately an SVG rasterized to PNG, a browser is a lot of machine to pay for.
Vercel's Satori gets closer to the metal. It converts JSX into SVG, which is honest work, but you still assemble the rest of the pipeline yourself: font loading, layout edge cases, SVG to PNG conversion, an HTTP wrapper if you want an API. It is a component, not a service.
The listicles of "Bannerbear alternatives" mostly list other SaaS. Between hosted subscriptions and a self-assembled Chromium pipeline, the pure-Rust option rarely comes up. That gap is why we built Cosy, and why this post exists.
How Cosy works
The pipeline is one line: an SVG template with {{ tokens }} plus a JSON schema becomes minijinja substitution, then resvg rasterization, then a PNG out. Templates are plain SVG files, so any vector editor can author them. A schema.json next to each template declares the fields, types, and defaults, and cosy validate checks input data against it before you render.
The binary ships with 152 built-in templates: og-image for social cards, blog-hero for article headers, twitter-quote, linkedin-card, benchmark-result, changelog, and so on. Rendering one card from the command line looks like this:
cosy render -t og-image --json '{"brand":{"brand_name":"CodeCora","show_brand":false},"slides":[{"title":"Timing test slide","tag":"Test"}]}' -o card.png
That command is real. We ran it five times while writing this post to time it.
For programmatic use, cosy serve starts an HTTP API. POST /api/render takes the same JSON and returns PNG bytes. A multi-slide mode shipped in September: send response_format: "json" and the API renders every slide of a carousel, returning base64 PNG entries with template dimensions, or pick a single slide with slide_index. Empty slide arrays and out-of-range indices get rejected with a 400, which is the kind of boring validation you want in a render service.
The numbers, measured
We timed the CLI on our build server, rendering the same 1200x630 og-image card five times:
- 150 ms median per render, cold process start included
- 13 MB single binary, no runtime dependencies
- 152 templates built in
The cold number includes loading the binary and its bundled fonts each run. An in-process render through the HTTP server skips that cost, and the project's README quotes roughly 50 ms per slide for the warm path. Either way, the comparison holds: cloud template APIs advertise seconds per image, and a Chromium screenshot pipeline pays a browser boot before it draws the first pixel.
Honest context: the GitHub repo has 1 star. Cosy is early, version 0.2.0, and we are its heaviest user. These are numbers from our own pipeline, published so you can reproduce or discount them.
Trade-offs worth knowing
The license first, because it matters. Cosy is not OSI open source. It ships under the Business Source License 1.1 with an Additional Use Grant that covers personal use, internal business use, and non-commercial open-source projects, free. The license converts to Apache 2.0 on August 11, 2029. Commercial or SaaS deployment before that date means contacting us for a license. We would rather state that plainly in the first post about the tool than have anyone discover it in a legal file.
Second trade-off: templates constrain design. You get brand consistency, predictable layouts, and renders you can regenerate forever, but you do not get bespoke art direction. We made the case for templates over AI-generated art in an earlier post, Same Data In, Five Different Posters Out. This post is about the other half of that argument, the self-hosting and architecture side.
Third: Cosy renders, it does not generate. There is no AI image generation and no photo editing. If a task needs original artwork, this is the wrong tool. If a task needs the same card layout with different numbers, titles, and accent colors, this is exactly the tool.
Where it fits
Cosy fits teams that already self-host and want image generation to be one more local service: an OG image per blog post, changelog banners per release, social cards from data your systems already have. It fits CI pipelines that produce marketing visuals as a build step. It fits the case where the alternative was "keep a headless browser warm for screenshots."
It does not fit design-team workflows. If the job is exploratory visual work, Canva and its peers remain the right shape for that job, and no amount of render speed changes it.
What's next
Development moves in small, shippable steps. The last two weeks alone brought the multi-slide HTTP API, text autofit driven by slot metrics, inline text markup with real font faces, and notebook-style templates with handwritten fonts. Commits landed as recently as September 23. The near-term focus is more templates and sharper API ergonomics, not a rewrite of what already works.
The repo is at github.com/codecoradev/cosy. Build it, run cosy templates, render one card. Then time whatever your current image pipeline does, and compare.