Performance & Optimization
Reuse rendering work and measure before tuning caches.
Reuse the renderer
import { } from "takumi-js";
const = await (< ="p-8 text-4xl">Hello Takumi</>, {
: 1200,
: 630,
});render and ImageResponse reuse a managed renderer. No cache setup is needed. When using Renderer directly, create it outside the request handler so registered fonts and decoded resources survive between renders.
Know what is cached
| Work | Lifetime | Configuration |
|---|---|---|
| Decoded images, SVG rasters, parsed stylesheets | Renderer | cacheMaxBytes, 16 MiB by default |
| Glyph outlines and rasterized masks | Loaded backend module | setGlyphCacheMaxBytes, 8 MiB by default |
| Parsed Tailwind classes | Loaded backend module | Automatic, bounded internally |
| Resolved Tailwind declarations | Render | Automatic, separated by viewport width, font size, and pixel ratio |
| Google Fonts CSS | Fetch implementation | Automatic, bounded internally |
| Downloaded image bytes | Caller-provided cache | Optional images.fetchCache |
Cache budgets account for retained entries, not total process memory. Fonts, active renders, output buffers, and allocator overhead use memory too. See image caching and Google Fonts for resource-specific behavior.
Measure cold and repeated renders
Measure the first render separately from repeated renders. Font downloads and decoding affect startup; layout, painting, and encoding still happen on a warm renderer.
Use representative text, images, output formats, and concurrent requests. Compare latency and memory before changing a budget. Increasing a cache helps only when it keeps work that later renders reuse.
Resource cache
import { } from "takumi-js/node";
const = new ({ : 64 * 1024 * 1024 });Raise the budget when frequently reused images or stylesheets are being evicted. For images used only once, cache: "none" avoids displacing reusable entries. An unbounded images.fetchCache is separate from this budget.
Glyph cache
import { } from "takumi-js";
(64 * 1024 * 1024);Call this before the first render. Outlines and masks share the budget across renderers in the same backend module. Large glyph sets or text sizes can benefit from more space, but benchmark your content first.
Keep network requests out of repeated work
Bundle fonts for predictable startup without a font service. WOFF2 saves transfer and storage space but needs decompression; TTF avoids that step. A reused renderer decodes a registered file once. See local fonts and CI.
For repeated remote images, use a bounded fetch cache. The renderer's decode cache does not replace a download cache.
Reduce painting work
Each filtered node needs an offscreen layer. Put filters on one node when they should apply to the same composed content. Moving filters from children to a parent can change the output, so compare the result.
On servers, the native backend supports multithreaded rendering. The Wasm backend is single-threaded. takumi-js selects the backend for the environment; use explicit backend imports only when you need to control that choice.
Last updated on