---
name: Image Generation
description: Generate images from a prompt with generateImage(), persist them with writeBinary(), and feed them back into multimodal llm() calls.
---

# Image Generation

Import `generateImage` from `std::image`:

```ts
import { generateImage } from "std::image"

node main() {
  const r = generateImage("a red bicycle in the rain", size: "1024x1024")
  if (isFailure(r)) {
    print("generation failed: ${r.error}")
    return
  }
  const img = r.value          // { base64: string, mimeType: string }
  writeBinary("bike.png", img.base64)
  print("saved bike.png")
}
```

`generateImage` returns a `Result`. On success, its value is a `{ base64,
mimeType }` object — the image is returned in memory as base64, not written to
disk automatically.

## Saving the image

`writeBinary(path, base64)` decodes base64 and writes the raw bytes — use it for
any binary data (images, audio, video, PDFs). It's auto-imported, so no import is
needed.

Read a binary file back with `readBinary(path)`, which returns the contents as
base64.

## Sending a generated image in an LLM call

Images generated by `generateImage` are not added to the current message thread, so if you want to ask a question about it, for example, you have to send it along with your message. Once it's sent, though, it is part of the message thread, and you don't need to send it again. Note that images do bloat the context of message threads.

How to send the image:

```ts
import { generateImage } from "std::image"
import { image } from "std::thread"

node main() {
  const imageResult = generateImage("a red bicycle")
  match(imageResult) {
    failure(error) => print("generation failed: ${error}")
    success(img) => {
      const answer = llm([
        "What color is the bicycle in this image?",
        image(img.base64, img.mimeType, base64: true),
      ])
      print(answer)
    }
  }
}
```

## Editing images

You can pass images in to edit them. Each entry is a path, an `http(s)`
URL, or a `data:` URI.

```ts
const edited = generateImage("make it nighttime", images: ["bike.png"])
```

## Choosing a provider and model

By default, `generateImage` uses OpenAI's image model. You can override the model or provider per call.

```ts
// OpenAI (default)
generateImage("a red bike")

// Google's "nano banana" (Gemini 2.5 Flash Image). The provider is derived
// from the model name, so you only need `model`. Set GEMINI_API_KEY.
generateImage("a red bike", model: "gemini-2.5-flash-image")

// The higher-tier "nano banana pro"
generateImage("a red bike", model: "nano-banana-pro-preview")

// An open-source model via LiteLLM
generateImage("a red bike", provider: "litellm", model: "flux-pro",
              baseUrl: "https://your-litellm-host")

// Together AI (OpenAI-compatible images endpoint)
generateImage("a red bike", provider: "openai-compat",
              model: "black-forest-labs/FLUX.1-schnell",
              baseUrl: "https://api.together.ai/v1")
```

Options:

| Option | Description |
| --- | --- |
| `model` | Image model (default: the provider's default image model). |
| `provider` | eg "google", "openai-compat", "litellm" |
| `size` | Image size, e.g. `"1024x1024"` (provider-dependent). |
| `quality` | `"low"` / `"medium"` / `"high"` / `"auto"`. |
| `images` | Input images to edit/vary, as path / URL / data-URI strings. |
| `apiKey` | API key (reads env vars `OPENAI_API_KEY`, `GEMINI_API_KEY`, etc. if not set) |
| `baseUrl` | Base URL for `openai-compat` / `litellm` providers. |

## Limitations

- Local image generation is not yet supported.
- One image per call.
- No mask-based inpainting yet.