Skip to content

Memory ​

A render keeps several copies of the image in memory at once. estimateMemoryMB(width, height) returns the peak for an original of that size: 24 bytes per pixel plus 256 MB for the runtime.

ts
import { estimateMemoryMB } from '@sealpixel/render';

estimateMemoryMB(8000, 6000); // 1408
OriginalMegapixelsEstimateLambda size to start from
4000 × 300012544 MB1024 MB
6000 × 400024832 MB1769 MB (one full vCPU)
8660 × 5774501457 MB2048 to 3008 MB

The core runs on one thread. On Lambda, the 1769 MB tier gives one full vCPU, so memory also sets the speed.

limits.maxMegapixels is the size you have to plan for. The renderer refuses a larger original from its header, before it decodes a pixel. The TOO_LARGE message names the memory that the original would need.

Concurrent renders ​

One render runs at a time per process. Concurrent calls of render() run their checks at once, but the decode, the render and the encode run one after another. A render that waits holds only the encoded bytes of its original and its assets, not a decoded image. The peak is therefore about one render plus the encoded input bytes of the waiting requests. More concurrent requests make the process slower per request, not larger.

Where the bytes go ​

Measured on Node 24 with a JPEG original, per pixel of the original:

WhereBytes per pixel
WebAssembly memory, heaviest stage (annotate, sticker, frame, watermark: the input, a premultiplied copy and the output)12
WebAssembly memory, crop9
WebAssembly memory, color, redact, resize4 to 5
The decoded image and the rendered image as JS arrays8
One render, process peak above the idle runtime19 to 24

The renderer decodes the original once and passes the decoded image to the render. WebAssembly memory grows to its peak and does not shrink, so it stays allocated for the life of the process.

result.stream() does not lower the peak. The encoder builds the whole file in memory, and the stream starts after that.

The ceiling ​

The core accepts at most 2^28 pixels (268 megapixels, 16384 × 16384) and 65535 pixels per side, for the original and for the output of every stage. A plan whose output is larger fails with TOO_LARGE before the core allocates the buffer.