Generate 50 banners in one go with Node.js - but stop writing your SVG text by hand
A Node.js pipeline produces fifty variations of social visuals in less than a minute. Sharp for compositing and optimization, Satori for text - and everything else you don't want to code by hand.
The bottleneck of social visuals
When you're managing the social networks of an active brand, the production of visuals quickly becomes unmanageable. Every publication requires variations for Instagram, X, LinkedIn and the Open Graph image - a minimum of four formats per content. Multiply that by five publications a week, and you end up producing twenty weekly visuals by hand. This pace is unsustainable.
The programmatic approach consists of defining templates as code, injecting dynamic content into them, and automatically generating all the variants. A script that runs in seconds replaces hours of cut-and-paste in Photoshop, and the result is perfectly consistent from one variant to the next. This is the approach I use for my clients: fifty banners from a single template, in less than a minute. But there's one particular place where most tutorials waste your time, and I'll get to that.
Sharp: the composition and optimization engine
Sharp encapsulates libvips, an extremely fast C++ image processing engine - several times faster than pure JavaScript alternatives. It accepts JPEG, PNG, WebP, AVIF, TIFF, GIF and SVG as input and output. Version 0.34, released in Q1 2026, brought things that matter for a production pipeline: first-class AVIF encoding via libavif, native HEIC decoding without a separate license key, a hardened WASM build to reduce cold starts in serverless, and a pool of process workers. In concrete terms, this makes serverless deployment much cleaner than it was a year ago.
The API is a chain of transformations: load a source, resize, compose layers, export.
js import sharp from "sharp";
await sharp("background.jpg") .resize(1200, 630) .composite([ { input: logoBuffer, gravity: "northwest" }, { input: textSvgBuffer, gravity: "center" }, ]) .toFormat("webp", { quality: 80 }) .toFile("output.webp");
Its limitation is that it has no native text rendering. To add text, you have to pass it an SVG overlay, which it then rasterizes - and that's exactly where many get bogged down.
## For text, don't write SVG by hand: Satori
Building a text SVG fragment by hand, calculating positions, line breaks and font adjustment, is tedious and fragile. As soon as the text is dynamic - an article title of variable length - it breaks. The right answer in 2026 is Satori, Vercel's library (version 0.18) that converts HTML and CSS to SVG without a headless browser, supporting flexbox and a large subset of CSS. It's the engine behind `@vercel/og` (version 0.11), which powers thousands of Next.js social maps.
```jsx
// Satori: you're writing JSX/CSS, not SVG <text> by hand
const svg = await satori(
<div style={{ display: "flex", flexDirection: "column", padding: 64,
background: "#0b1020", color: "white", width: 1200, height: 630 }}>
<h1 style={{ fontSize: 64, fontWeight: 700 }}>{title}</h1>
<p style={{ fontSize: 28, opacity: 0.8 }}>{excerpt}</p>
</div>,
{ width: 1200, height: 630, fonts: [/* ... */] }
);
My rule became simple: Satori produces the text SVG with a real layout, and Sharp takes care of what it does best - compositing that SVG onto a background, rasterizing, optimizing and exporting. Each in its own place.
Separating template from content
The key to a maintainable system is to never mix template definition and content. I define each template as a configuration object: dimensions, layers, positions, styles, dynamic text zones. The rendering engine reads this config, loads the assets, injects the data and produces the image. Adding a format is done by adding a configuration object, without touching the rendering code. Tip that saved me on multi-format: I position elements in relative percentages rather than absolute pixels, which means I can switch from one ratio to another without recalculating everything.
As for the choice of engine according to need, here's how I decide.
| Tool | Role | When to use it |
|---|---|---|
| Sharp | composition, rasterization, optimization | foundation of any pipeline |
| Satori / @vercel/og | HTML/CSS → SVG | any dynamic text visual |
| node-canvas (Cairo) | API Canvas 2D server | text rendering without SVG |
| Puppeteer / Playwright | screenshot of an HTML page | very complex compositions, full CSS |
| Bannerbear, Cloudinary, Placid | SaaS + API REST | teams with no desire to maintain code |
A word about Jimp, often cited as a pure JavaScript alternative: it has been rewritten in TypeScript and released in version 1.x. It's still handy for avoiding native dependencies, but its performance remains well below Sharp's - I only use it for specific deployment constraints.
The production pipeline
In production, I integrate generation into a wider workflow. A webhook is triggered when an article is published in the CMS; the Node.js script retrieves the title, extract and front-page image, generates the visuals for all platforms, optimizes them and deposits them in an S3 bucket behind a CDN. All the social network manager has to do is plan the publication, with the visuals already ready.
Weight optimization is critical: I aim for a maximum of 300 Kb per visual for fast loading on mobile. WebP offers an excellent compromise between quality and weight, and with AVIF now first-class in Sharp 0.34, I use it when the target platform supports it. The gain measured on my projects is clear: two to three hours of weekly graphics work replaced by less than a minute of execution. But the real benefit isn't time - it's consistency. Each visual respects exactly the same margins, fonts and composition rules, without the variability inherent in repeated manual work. And by entrusting the text to Satori rather than to cobbled-together SVG <text>, the system no longer breaks whenever a title exceeds the expected length.
The social visual that converts takes 2 seconds - and most designers are optimizing the wrong thing
A banner has two seconds to stop the scroll. In 2026, a 4:5 master covers almost everything and AI manages production - the real conversion lever lies elsewhere, and most designers ignore it.
Instagram carousel: 80% of the work is done on slide 1 (and slide 3 gives you away)
There's nothing magical about the 10-slide structure. In 2026, the algorithm rewards sharing and punishes recycling - here's where to really put your energy for a carousel that shares.
AI email pipeline: copywriting is not the problem - since November 2025, Gmail has been rejecting your non-compliant mailings
Automating the writing of an email is easy. What decides whether it happens is compliance - and Gmail now definitively rejects out-of-standard senders. The complete architecture of a passing IA email pipeline.