Takumi

Nitro

Return Open Graph images from Nitro server routes with Takumi node helpers and ImageResponse.

Build an Open Graph image from a node tree and return it from a Nitro route. The helpers build the tree, so the route needs no JSX setup.

Install Takumi

npm i takumi-js

Create a server route

Nitro handlers can return a Response, so return the ImageResponse directly.

routes/og.png.ts
import { defineHandler } from "nitro";
import { container, text } from "takumi-js/helpers";
import ImageResponse from "takumi-js/response";

export default defineHandler((event) => {
  const url = new URL(event.req.url);
  const title = url.searchParams.get("title") ?? "Takumi + Nitro";
  const description =
    url.searchParams.get("description") ?? "Render OG images from a Nitro route.";

  return new ImageResponse(
    container({
      style: {
        width: "100%",
        height: "100%",
        display: "flex",
        flexDirection: "column",
        justifyContent: "center",
        padding: "64px",
        backgroundImage: "linear-gradient(to bottom right, #fff1f2, #fecdd3)",
      },
      children: [
        text(title, { fontSize: 72, fontWeight: 700, color: "#111827" }),
        text(description, { fontSize: 42, fontWeight: 500, color: "#4b5563" }),
      ],
    }),
    {
      width: 1200,
      height: 630,
    },
  );
});

Request the endpoint

Visit /og.png?title=Hello&description=From%20Nitro.

Choose the backend

Every Nitro preset renders on the WebAssembly backend by default. While wasm is on, which is the default, Nitro sets the unwasm export condition. Takumi then ships its WebAssembly binary inside your server bundle. No native addon has to resolve at runtime, so the same route runs on an edge preset and in a WebContainer, such as StackBlitz or CodeSandbox.

To use the native binding on the Node.js preset, negate the condition:

nitro.config.ts
import { defineConfig } from "nitro";

export default defineConfig({
  exportConditions: ["!unwasm"],
});

wasm: false also selects the native binding, but it removes unwasm from the build. Other .wasm imports in your app then stop resolving. Negating the condition keeps the plugin.

Last updated on