Image generation
Generate images from natural language prompts and remove backgrounds from existing images.
Why Use AI Image Generation
Your application needs custom imagery: a hero illustration that matches a user's prompt, an avatar based on a description, a product mock-up for an e-commerce listing, or a clean cut-out for a profile photo. Using a stock library is too generic, and integrating with each model provider directly means juggling API keys, request shapes, polling logic, and storage.
Squid AI Image gives you a single backend API for several image models and a built-in background removal endpoint:
- TypeScript
- Python
const url = await this.squid.ai().image().generate('a pirate ship at sunset, oil painting style', {
modelName: 'dall-e-3',
size: '1024x1024',
quality: 'hd',
});
url = await self.squid.ai().image().generate(
'a pirate ship at sunset, oil painting style',
{'modelName': 'dall-e-3', 'size': '1024x1024', 'quality': 'hd'},
)
Overview
Squid AI Image wraps three families of image models behind a single client:
- OpenAI DALL-E 3 for general-purpose photorealistic and stylized images
- Stability AI Stable Diffusion Core for style presets, aspect ratio control, and background removal
- Black Forest Labs Flux Pro / Flux Kontext Pro for high-quality generation with explicit width/height control
The Squid backend authenticates the request, looks up the right provider API key from your application configuration, calls the upstream model, and returns a URL to the generated image.
When to use AI Image
| Use Case | Recommendation |
|---|---|
| Generate a one-off image from a text prompt | generate() with the model that fits your style needs |
| Strip the background from an uploaded photo | removeBackground() |
| Show generated images inside an AI agent | Attach an AI function that calls generate() and returns the URL |
| Long-term storage of generated assets | Upload the returned image to Squid storage |
How it works
- You call
this.squid.ai().image().generate(prompt, options)from a backend service - Squid validates the model and options, then routes the call to the matching provider (OpenAI, Stability, or Black Forest Labs)
- The provider generates the image and returns a URL
- The Squid backend returns that URL to your code
- The URL is temporary. If you need to keep the image, download it and re-upload to Squid storage or your own bucket.
Quick Start
Prerequisites
- A Squid backend project initialized with
squid init - The
@squidcloud/backendpackage (TypeScript) orsquidcloud-backendpackage (Python) - The relevant AI provider enabled in the Squid Console (OpenAI, Stability AI, or Black Forest Labs, depending on which model you call)
Step 1: Wrap the call in an executable
Image generation requires admin access, so it must run on the backend. Wrap it in an executable so a client can trigger it without leaking API keys.
- TypeScript
- Python
import { executable, SquidService } from '@squidcloud/backend';
import { AiGenerateImageOptions } from '@squidcloud/client';
export class ImageService extends SquidService {
@executable()
async generateImage(prompt: string): Promise<string> {
this.assertIsAuthenticated();
const options: AiGenerateImageOptions = {
modelName: 'dall-e-3',
quality: 'standard',
size: '1024x1024',
};
return this.squid.ai().image().generate(prompt, options);
}
}
from squidcloud_backend import SquidService, executable
class ImageService(SquidService):
@executable()
async def generate_image(self, prompt: str) -> str:
self.assert_is_authenticated()
options = {
'modelName': 'dall-e-3',
'quality': 'standard',
'size': '1024x1024',
}
return await self.squid.ai().image().generate(prompt, options)
Step 2: Run or deploy the backend
squid start
To deploy to the cloud, see deploying your backend.
Step 3: Call from the client
const imageUrl = await squid.executeFunction('generateImage', 'a friendly squid mascot, vector art');
document.querySelector<HTMLImageElement>('#preview')!.src = imageUrl;
Authentication and Configuration
Image methods require an authenticated Squid client with admin access. Both generate() and removeBackground() reject calls that do not originate from a backend or admin context.
The two recommended patterns are:
- Wrap calls in executables, as shown in Quick Start. This is the standard pattern for client-triggered image generation. See executables.
- Call from a privileged backend service, such as a trigger, scheduler, or webhook.
The provider API keys (OpenAI, Stability, Flux) live in your Squid Console application configuration. Squid looks the right key up at request time based on the modelName you pass.
Core Concepts
Supported models
AiGenerateImageOptions is a discriminated union on modelName. The field determines which option set is valid and which provider is called:
| Model | Provider | Options type |
|---|---|---|
dall-e-3 | OpenAI | DallEOptions |
stable-diffusion-core | Stability AI | StableDiffusionCoreOptions |
flux-pro-1.1 | Black Forest Labs | FluxOptions |
flux-kontext-pro | Black Forest Labs | FluxOptions |
DALL-E 3 options
| Field | Type | Required | Description |
|---|---|---|---|
modelName | 'dall-e-3' | Yes | Selects the DALL-E 3 model |
quality | 'hd' | 'standard' | No | Image quality. Defaults to 'standard'. |
size | '1024x1024' | '1792x1024' | '1024x1792' | No | Output dimensions. Defaults to '1024x1024'. |
numberOfImagesToGenerate | 1 | No | DALL-E 3 only supports a single image per call |
Stable Diffusion Core options
| Field | Type | Required | Description |
|---|---|---|---|
modelName | 'stable-diffusion-core' | Yes | Selects the Stable Diffusion Core model |
aspectRatio | string | No | One of '16:9', '1:1', '21:9', '2:3', '3:2', '4:5', '5:4', '9:16', '9:21'. Defaults to '1:1'. |
negativePrompt | string | No | Describe what to exclude from the image |
seed | number | No | Set a fixed seed for reproducible output |
stylePreset | string | No | One of 'analog-film', 'anime', 'cinematic', 'comic-book', 'digital-art', 'enhance', 'fantasy-art', 'isometric', 'line-art', 'low-poly', 'modeling-compound', 'neon-punk', 'origami', 'photographic', 'pixel-art', 'tile-texture' |
outputFormat | 'jpeg' | 'png' | 'webp' | No | Output image format. Defaults to 'png'. |
Flux options
| Field | Type | Required | Description |
|---|---|---|---|
modelName | 'flux-pro-1.1' | 'flux-kontext-pro' | Yes | Selects which Flux model to use |
width | number | No | Multiple of 32, between 256 and 1440. Defaults to 1024. |
height | number | No | Multiple of 32, between 256 and 1440. Defaults to 768. |
prompt_upsampling | boolean | No | When true, the provider rewrites the prompt for more creative output |
seed | number | No | Integer seed for reproducible output |
safety_tolerance | number | No | Integer between 1 (strictest) and 5 (most permissive) |
Return value
generate() returns a Promise<string> (TypeScript) or str (Python). The string is a URL pointing at the generated image. The URL is temporary, with provider-specific lifetimes:
- DALL-E: OpenAI hosted URL, valid for roughly one hour
- Stable Diffusion Core: signed URL pointing at Squid storage; the underlying file is retained for one day
- Flux: signed URL hosted by Black Forest Labs
If you need long-lived access to the image, download it from the URL and re-upload it to your own Squid storage bucket.
Background removal
removeBackground() accepts an image file and returns a URL pointing at the same image with the background stripped out. It always uses Stable Diffusion under the hood (you do not pick a model). Stability AI must be enabled on your application for this method to work.
| Method | TypeScript signature | Python signature |
|---|---|---|
removeBackground | (file: File) => Promise<string> | (image_data: bytes, filename: str = "image.png", content_type: str = "image/png") -> str |
Code Examples
Generate with Stable Diffusion using a style preset
- TypeScript
- Python
import { executable, SquidService } from '@squidcloud/backend';
export class ImageService extends SquidService {
@executable()
async generateAnimePoster(subject: string): Promise<string> {
this.assertIsAuthenticated();
return this.squid.ai().image().generate(subject, {
modelName: 'stable-diffusion-core',
stylePreset: 'anime',
aspectRatio: '2:3',
outputFormat: 'png',
negativePrompt: 'low quality, blurry, watermark',
});
}
}
from squidcloud_backend import SquidService, executable
class ImageService(SquidService):
@executable()
async def generate_anime_poster(self, subject: str) -> str:
self.assert_is_authenticated()
return await self.squid.ai().image().generate(
subject,
{
'modelName': 'stable-diffusion-core',
'stylePreset': 'anime',
'aspectRatio': '2:3',
'outputFormat': 'png',
'negativePrompt': 'low quality, blurry, watermark',
},
)
Generate with Flux at a specific resolution
- TypeScript
- Python
const url = await this.squid.ai().image().generate('a glass terrarium with bonsai trees', {
modelName: 'flux-pro-1.1',
width: 1024,
height: 1024,
safety_tolerance: 2,
seed: 42, // Deterministic output
});
url = await self.squid.ai().image().generate(
'a glass terrarium with bonsai trees',
{
'modelName': 'flux-pro-1.1',
'width': 1024,
'height': 1024,
'safety_tolerance': 2,
'seed': 42, # Deterministic output
},
)
Generate, then persist the result to Squid storage
The provider URL is temporary. If you want to keep the image around, download it and re-upload it to a Squid storage bucket.
- TypeScript
- Python
import { executable, SquidService } from '@squidcloud/backend';
export class GalleryService extends SquidService {
@executable()
async generateAndStore(prompt: string): Promise<{ url: string }> {
this.assertIsAuthenticated();
const tempUrl = await this.squid.ai().image().generate(prompt, {
modelName: 'dall-e-3',
size: '1024x1024',
quality: 'hd',
});
// Download the image bytes from the temporary URL.
const response = await fetch(tempUrl);
if (!response.ok) {
throw new Error(`Failed to download generated image: ${response.status}`);
}
const arrayBuffer = await response.arrayBuffer();
// Upload to Squid storage so the image is available long-term.
const storage = this.squid.storage('gallery');
const fileName = `${crypto.randomUUID()}.png`;
const file = new File([arrayBuffer], fileName, { type: 'image/png' });
await storage.uploadFile('generated', file);
const { url } = await storage.getDownloadUrl(`generated/${fileName}`);
return { url };
}
}
import base64
import httpx
from squidcloud_backend import SquidService, executable
class GalleryService(SquidService):
@executable()
async def generate_and_return(self, prompt: str) -> dict:
self.assert_is_authenticated()
temp_url = await self.squid.ai().image().generate(
prompt,
{'modelName': 'dall-e-3', 'size': '1024x1024', 'quality': 'hd'},
)
# Download the image bytes from the temporary URL before it expires.
async with httpx.AsyncClient() as http:
response = await http.get(temp_url)
response.raise_for_status()
image_bytes = response.content
# Return the image inline as base64. For long-term hosting, upload from
# the TypeScript backend or your own storage layer.
return {
'base64': base64.b64encode(image_bytes).decode('ascii'),
'mimeType': 'image/png',
}
Remove background from a client upload
- TypeScript
- Python
import { executable, SquidFile, SquidService } from '@squidcloud/backend';
export class ImageService extends SquidService {
@executable()
async stripBackground(image: SquidFile): Promise<string> {
this.assertIsAuthenticated();
if (!image.mimetype.startsWith('image/')) {
throw new Error('Only image files are accepted');
}
const file = new File([image.data], image.originalName, { type: image.mimetype });
return this.squid.ai().image().removeBackground(file);
}
}
from squidcloud_backend import SquidFile, SquidService, executable
class ImageService(SquidService):
@executable()
async def strip_background(self, image: SquidFile) -> str:
self.assert_is_authenticated()
if not image['mimetype'].startswith('image/'):
raise ValueError('Only image files are accepted')
return await self.squid.ai().image().remove_background(
image['data'],
image['originalName'],
image['mimetype'],
)
Error Handling
Common errors
| Error | Cause | Solution |
|---|---|---|
UNAUTHORIZED | Image method called from a non-admin context (e.g. browser without backend wrapping) | Wrap the call in an executable or call from backend code |
Unsupported image model name | modelName is not in the supported list | Use one of dall-e-3, stable-diffusion-core, flux-pro-1.1, flux-kontext-pro |
Invalid width: <n> (Flux) | Width is not an integer between 256 and 1440 or not a multiple of 32 | Round to the nearest valid value |
Invalid height: <n> (Flux) | Height is not an integer between 256 and 1440 or not a multiple of 32 | Round to the nearest valid value |
Invalid safety tolerance (Flux) | safety_tolerance is not an integer between 1 and 5 | Use a value in [1, 5] |
Image generation timed out (Flux) | The provider job did not finish within the polling window | Retry, or fall back to another model |
Method not implemented (background removal) | Background removal was attempted with a non-Stability provider | Call removeBackground() directly. It always uses Stable Diffusion regardless of context. |
MUST_PROVIDE_FILE | removeBackground() was called without a file | Pass a non-empty File (TypeScript) or bytes (Python) |
Validate input early
Reject obviously bad input in your executable rather than waiting for the upstream provider to fail:
- TypeScript
- Python
@executable()
async safeGenerate(prompt: string): Promise<string> {
this.assertIsAuthenticated();
if (!prompt || prompt.length < 3) {
throw new Error('Prompt must be at least 3 characters');
}
if (prompt.length > 1000) {
throw new Error('Prompt must be 1000 characters or less');
}
return this.squid.ai().image().generate(prompt, {
modelName: 'dall-e-3',
});
}
@executable()
async def safe_generate(self, prompt: str) -> str:
self.assert_is_authenticated()
if not prompt or len(prompt) < 3:
raise ValueError('Prompt must be at least 3 characters')
if len(prompt) > 1000:
raise ValueError('Prompt must be 1000 characters or less')
return await self.squid.ai().image().generate(
prompt,
{'modelName': 'dall-e-3'},
)
Best Practices
- Always wrap image calls in executables. Image methods require admin access, so they cannot be called directly from a browser.
- Pick a model that matches the use case. DALL-E 3 is a strong default for general-purpose images. Stable Diffusion Core wins when you need style presets or aspect ratio control. Flux gives explicit width/height control and reproducible seeds.
- Persist images you care about. Provider URLs expire. Download and re-upload to Squid storage for long-term hosting.
- Reject bad input early. Validate prompt length and file type before calling the model.
- Apply rate limiting to image executables. Image generation is one of the most expensive AI operations and is a common target for abuse.
- Cache by prompt + options. Identical prompts with the same
seedproduce identical results in Flux and Stable Diffusion. Cache by a hash of(prompt, options)to save quota.
See Also
- Executables - Wrap image calls so they can be called from a client
- AI agent - Build an AI agent that can generate images via an AI function
- Storage - Persist generated images for long-term access
- Rate and quota limiting - Protect image executables from abuse