Takumi

ImageResponse

Return rendered images from HTTP route handlers with the next/og-compatible ImageResponse API.

Return an ImageResponse from a route handler to serve a rendered image. It extends the web Response, so it works in any runtime with Request and Response. Its API matches next/og.

app/og/route.tsx
import {  } from "takumi-js/response";

export function () {
  return new (<>Hello Takumi</>, { : 1200, : 630 });
}

The first argument takes what render() takes: JSX, an HTML string, or a node tree.

Options

ImageResponseOptions is the render() options plus the ResponseInit fields and an error hook.

Prop

Type

Description

width?number

Image width in pixels. Omit it to size the width to the content.

height?number

Image height in pixels. Omit it to size the height to the content.

format?"png" | "jpeg" | "webp" | "ico" | "raw"

Output encoder. Also sets the default content-type.

quality?number

Encoder quality, 0–100. Applies to JPEG and lossy WebP.

fonts?FontLoader[] | Promise<FontLoader[]>

Fonts for this response. Each file decodes once per renderer.

css?CssInput | CssInput[]

Stylesheet text or rule objects.

images?ImageLoader[] | { sources, fetchCache, cache, ...fetchOptions }

Pre-fetched images keyed by src, and limits for the images Takumi fetches.

renderer?Renderer

A renderer you configured yourself.

jsx?FromJsxOptions

JSX conversion options, such as { defaultStyles: false }.

signal?AbortSignal

Cancels the render while it loads fonts and images.

headers?HeadersInit

Response headers. content-type defaults to match format.

status?number

Response status code.

statusText?string

Response status text.

onError?(error: unknown) => void | Promise<void>

Runs after a render fails. Defaults to logging the error with console.error.

Custom headers

content-type follows format unless you set it. Takumi sets no other headers. This handler lets browsers and shared caches reuse the image for one hour:

Cache an image response
import {  } from "takumi-js/response";

export function () {
  return new (<>Hello Takumi</>, {
    : 1200,
    : 630,
    : "webp",
    : {
      "Cache-Control": "public, max-age=3600",
    },
  });
}

Match max-age to how often the content changes.

Error handling

The response streams its body while the render runs, so the status is already set when a render fails. To send a fallback instead, await ready. It resolves when the render succeeds and rejects when it fails.

Return a fallback response
import {  } from "takumi-js/response";

export async function () {
  const  = new (<>Hello Takumi</>, { : 1200, : 630 });

  try {
    await .; 
    return ;
  } catch {
    return new ("Failed to generate image", { : 500 });
  }
}

onError is for side effects such as logging. Takumi ignores its return value, and the response stream still errors. Use ready to send a fallback.

Log a render failure
import {  } from "takumi-js/response";

export function () {
  return new (<>Hello Takumi</>, {
    : 1200,
    : 630,
    : () => .(), 
  });
}

Bring your own renderer

Without renderer, every response in the process shares one default renderer and its caches. Pass your own Renderer to configure it: set cache budgets, or register fonts up front.

Reuse a native renderer
import {  } from "takumi-js/node";
import {  } from "takumi-js/response";

const  = new ({ : 128 * 1024 * 1024 }); 

export function () {
  return new (<>Hello Takumi</>, {
    : 1200,
    : 630,
    , 
  });
}

takumi-js/node exports the native renderer. On WebAssembly runtimes, use the Renderer from takumi-js/wasm and call its init first, as in the measure() example.

Last updated on