Image Generation

AI Gateway supports image generation and editing capabilities. You can generate new images from text prompts, edit existing images, and create variations with natural language instructions.

You can view all available models that support image generation by using the Image filter at the AI Gateway Models page.

Google's Gemini 2.5 Flash Image model offers state-of-the-art image generation and editing capabilities. This model supports specifying response modalities to enable image outputs alongside text responses.

You can find details on this model in the Model Library.

Generate images from text prompts using the generateText function with appropriate provider options:

generate-image.ts
import 'dotenv/config';
import { generateText } from 'ai';
import fs from 'node:fs';
import path from 'node:path';
 
async function main() {
  const result = await generateText({
    model: 'google/gemini-2.5-flash-image-preview',
    providerOptions: {
      google: { responseModalities: ['TEXT', 'IMAGE'] },
    },
    prompt:
      'Render two versions of a pond tortoise sleeping on a log in a lake at sunset.',
  });
 
  if (result.text) {
    console.log(result.text);
  }
 
  // Save generated images to local filesystem
  const imageFiles = result.files.filter((f) =>
    f.mediaType?.startsWith('image/'),
  );
 
  if (imageFiles.length > 0) {
    // Create output directory if it doesn't exist
    const outputDir = 'output';
    fs.mkdirSync(outputDir, { recursive: true });
 
    const timestamp = Date.now();
 
    for (const [index, file] of imageFiles.entries()) {
      const extension = file.mediaType?.split('/')[1] || 'png';
      const filename = `image-${timestamp}-${index}.${extension}`;
      const filepath = path.join(outputDir, filename);
 
      await fs.promises.writeFile(filepath, file.uint8Array);
      console.log(`Saved image to ${filepath}`);
    }
  }
 
  console.log();
  console.log('Usage: ', JSON.stringify(result.usage, null, 2));
  console.log(
    'Provider metadata: ',
    JSON.stringify(result.providerMetadata, null, 2),
  );
}
 
main().catch(console.error);
stream-image.ts
import 'dotenv/config';
import { streamText } from 'ai';
import fs from 'node:fs';
import path from 'node:path';
 
async function main() {
  const result = streamText({
    model: 'google/gemini-2.5-flash-image-preview',
    providerOptions: {
      google: { responseModalities: ['TEXT', 'IMAGE'] },
    },
    prompt: 'Render a pond tortoise sleeping on a log in a lake at sunset.',
  });
 
  // Create output directory if it doesn't exist
  const outputDir = 'output';
  fs.mkdirSync(outputDir, { recursive: true });
  const timestamp = Date.now();
  let imageIndex = 0;
 
  for await (const delta of result.fullStream) {
    switch (delta.type) {
      case 'text-delta': {
        process.stdout.write(delta.text);
        break;
      }
 
      case 'file': {
        if (delta.file.mediaType.startsWith('image/')) {
          console.log();
 
          const extension = delta.file.mediaType?.split('/')[1] || 'png';
          const filename = `image-${timestamp}-${imageIndex}.${extension}`;
          const filepath = path.join(outputDir, filename);
 
          await fs.promises.writeFile(filepath, delta.file.uint8Array);
          console.log(`Saved image to ${filepath}`);
          imageIndex++;
        }
        break;
      }
    }
  }
  process.stdout.write('\n\n');
 
  console.log();
  console.log('Finish reason: ', result.finishReason);
  console.log('Usage: ', JSON.stringify(await result.usage, null, 2));
  console.log(
    'Provider metadata: ',
    JSON.stringify(await result.providerMetadata, null, 2),
  );
}
 
main().catch(console.error);
chatbot-with-images.ts
import { type ModelMessage, streamText } from 'ai';
import 'dotenv/config';
import * as readline from 'node:readline/promises';
import fs from 'node:fs';
import path from 'node:path';
 
const terminal = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
});
 
const messages: ModelMessage[] = [];
 
async function main() {
  // Create output directory if it doesn't exist
  const outputDir = 'output';
  fs.mkdirSync(outputDir, { recursive: true });
 
  while (true) {
    messages.push({ role: 'user', content: await terminal.question('You: ') });
 
    const result = streamText({
      model: 'google/gemini-2.5-flash-image-preview',
      providerOptions: {
        google: { responseModalities: ['TEXT', 'IMAGE'] },
      },
      messages,
    });
 
    process.stdout.write('\nAssistant: ');
    const timestamp = Date.now();
    let imageIndex = 0;
 
    for await (const delta of result.fullStream) {
      switch (delta.type) {
        case 'text-delta': {
          process.stdout.write(delta.text);
          break;
        }
 
        case 'file': {
          if (delta.file.mediaType.startsWith('image/')) {
            console.log();
 
            const extension = delta.file.mediaType?.split('/')[1] || 'png';
            const filename = `chat-image-${timestamp}-${imageIndex}.${extension}`;
            const filepath = path.join(outputDir, filename);
 
            await fs.promises.writeFile(filepath, delta.file.uint8Array);
            console.log(`💾 Saved image to ${filepath}`);
            imageIndex++;
          }
          break;
        }
      }
    }
    process.stdout.write('\n\n');
 
    console.log('Usage: ', JSON.stringify(await result.usage, null, 2));
    console.log(
      'Provider metadata: ',
      JSON.stringify(await result.providerMetadata, null, 2),
    );
 
    messages.push(...(await result.response).messages);
  }
}
 
main().catch(console.error);

Check the AI SDK provider documentation for more on provider/model-specific image generation configuration.

Generated images are returned as GeneratedFile objects in the result.files array. Each contains:

  • base64: The file as a base 64 data string
  • uint8Array: The file as a Uint8Array
  • mediaType: The MIME type (e.g., image/png, image/jpeg)

When using streamText, images are delivered through fullStream as file events:

for await (const delta of result.fullStream) {
  switch (delta.type) {
    case 'text-delta':
      // Handle text chunks
      process.stdout.write(delta.text);
      break;
 
    case 'file':
      // Handle generated files (images)
      if (delta.file.mediaType.startsWith('image/')) {
        await saveImage(delta.file);
      }
      break;
  }
}
Last updated on August 28, 2025