Skip to content
Batchwork
Esc
navigateopen⌘Jpreview
On this page

Images

Generate thousands of images in one batch with batch.images — the same job handle, base64 or hosted images per request.

Submit an image batch

batch.images() mirrors batch(): pass an image model and a list of prompts, and it returns the same BatchJob handle immediately. Each request produces one or more images, correlated by customId.

import { batch } from "batchwork";
import { openai } from "@ai-sdk/openai";

const job = await batch.images({
  model: openai.image("gpt-image-2"),
  requests: [
    { customId: "a", prompt: "A red bicycle against a brick wall." },
    { customId: "b", prompt: "A watercolor painting of a sleeping cat." },
  ],
});

const results = await job.wait().then(() => job.collect());
for (const r of results) {
  for (const image of r.images ?? []) {
    // Inline base64 (`image.data` + `image.mediaType`), or a hosted
    // `image.url` for providers that return one (e.g. xAI batch).
    console.log(r.customId, image.mediaType ?? image.url);
  }
}

Everything on the job handle works unchanged — wait(), poll(), results(), collect(), and cancel() — as does rehydration with getBatch / getBatchResults / cancelBatch.

You can also pass a "provider/model" string (e.g. "openai/gpt-image-2"), though the model object is recommended.

Supported providers

Batch image generation is available for the providers whose batch API accepts an image-generation endpoint:

Provider Example model Notes
OpenAI gpt-image-2 /v1/images/generations batch endpoint. Inline base64.
Google Gemini gemini-2.5-flash-image Gemini image models via :batchGenerateContent. Inline base64.
xAI grok-imagine-image-quality /v1/images/generations. Signed URLs that expire ~1h.

This is generation only — image editing (input images, masks) and video aren’t supported by the batch APIs.

Request shape

Each request is a text prompt plus an optional customId and a few generation knobs:

Field Notes
prompt The text describing the image to generate.
customId Correlates the result. Auto-generated as request-<index> if omitted; must be unique within a batch.
n Number of images to generate. Defaults to 1.
size Image size as "{width}x{height}" (e.g. OpenAI image models, "1024x1024").
aspectRatio Aspect ratio as "{width}:{height}" (e.g. Gemini image models, "16:9").
providerOptions Provider-specific options (e.g. { openai: { quality: "high" } }). See below.
seed Seed for deterministic generation, where the provider supports it.

limits and metadata work exactly as in batch().

Sizing, count, and provider options

size and aspectRatio are two ways providers express dimensions — OpenAI image models take a size like "1024x1024", while Gemini image models take an aspectRatio like "16:9". Pass whichever your model expects. Use n to request more than one image per prompt, and providerOptions (keyed by provider) for anything model-specific, the same shape the AI SDK’s generateImage uses:

// OpenAI — square 1024px, two variations, high quality
await batch.images({
  model: openai.image("gpt-image-2"),
  requests: [
    {
      customId: "a",
      prompt: "A red bicycle against a brick wall.",
      size: "1024x1024",
      n: 2,
      providerOptions: { openai: { quality: "high" } },
    },
  ],
});

// Google Gemini — widescreen aspect ratio
await batch.images({
  model: google.image("gemini-2.5-flash-image"),
  requests: [
    { customId: "a", prompt: "A sunlit forest path.", aspectRatio: "16:9" },
  ],
});

defaults are merged into every request (request-level values win), exactly as in batch() — handy for applying one size or providerOptions across the whole batch.

Results

Images reuse the normalized BatchResult. Generated images land on result.images, an array of { data?, mediaType?, url? }:

import { writeFile } from "node:fs/promises";

for await (const result of job.results()) {
  if (result.status === "succeeded") {
    for (const [i, image] of (result.images ?? []).entries()) {
      if (image.data) {
        // Inline base64 (OpenAI, Google) — no `data:` prefix.
        await writeFile(
          `${result.customId}-${i}.png`,
          Buffer.from(image.data, "base64")
        );
      } else if (image.url) {
        // Hosted URL (xAI batch) — fetch promptly; signed links expire ~1h.
        await fetch(image.url);
      }
    }
  } else if (result.status === "errored") {
    console.error(result.customId, result.error?.message);
  }
}

OpenAI and Google return inline base64 on image.data (with image.mediaType, e.g. "image/png"); xAI batch returns signed image.urls that expire ~1h after completion, so download them promptly. text and embedding are undefined for image batches.

usage is normalized to { inputTokens, totalTokens } where the provider reports it, billed at the batch rate (~50% off).

How it’s built

Like batch(), batch.images() derives each provider request body by running the AI SDK’s generateImage() through a capturing fetch that records the serialized body and aborts before any network call. Each request maps to a single image-generation call, correlated by customId.

Was this page helpful?