Image Transforms
Resize, reformat, and optimize images on the fly with URL-based options or named presets. No upload pipeline, no preprocessing — every image in a public bucket can be transformed at the edge and cached globally.
Why this exists
Modern apps need the same image at half a dozen sizes — a hero on desktop, a thumbnail in a list, a square avatar in a comment, an AVIF on phones that support it. Generating all of those at upload time is expensive and inflexible; new screen sizes mean re-processing everything.
Image transforms let you request a sized, formatted, optimized version of any image just by changing the URL. The result is cached at Cloudflare's edge for four hours, so subsequent requests cost nothing.
Two ways to transform
Pick the form that fits your use case.
Direct URLs
Encode options inline. Good for ad-hoc transforms, A/B tests, or one-off requests. The URL is self-describing — anyone reading it can see exactly what was requested.
https://cdn.koolbase.com/cdn-cgi/image/width=400,height=400,fit=cover,format=auto,quality=85/{project_id}/{bucket}/{path}Named presets
Store a set of options once on the server, reference it by name. Good for fixed sizes you reuse everywhere — thumbnail, hero, card. Change the preset, and every URL using it picks up the new options as the edge cache rolls over.
https://cdn.koolbase.com/p/{project_id}/{preset_name}/{bucket}/{path}Available options
All options are optional; omit any you don't need. The same set works for direct URLs and presets.
| Option | Type / values | Default |
|---|---|---|
| width | integer, 1–2000 | original |
| height | integer, 1–2000 | original |
| format | auto, webp, avif, jpeg, png | original |
| quality | integer, 1–100 | 85 |
| fit | scale-down, contain, cover, crop, pad | scale-down |
| dpr | integer, 1–3 | 1 |
| gravity | auto, center, top, bottom, left, right, top-left, top-right, bottom-left, bottom-right | center |
format=auto is usually what you want
Flutter SDK
The Flutter SDK builds both URL forms for you. Direct transforms with KoolbaseImageTransform:
final url = KoolbaseStorageClient.publicUrl(
projectId: koolbase.projectId,
bucket: 'avatars',
path: 'user_123.png',
transform: const KoolbaseImageTransform(
width: 200,
height: 200,
fit: KoolbaseImageFit.cover,
format: KoolbaseImageFormat.auto,
quality: 85,
),
);Or use a named preset:
final url = KoolbaseStorageClient.publicUrlWithPreset(
projectId: koolbase.projectId,
presetName: 'avatar',
bucket: 'avatars',
path: 'user_123.png',
);You can also chain off any KoolbaseObject you already have in hand:
final thumb = obj.publicUrlWithPreset('avatars', 'thumbnail');React Native SDK
Same two forms, TypeScript-typed.
const url = KoolbaseStorage.publicUrl({
projectId: koolbase.projectId,
bucket: 'avatars',
path: 'user_123.png',
transform: {
width: 200,
height: 200,
fit: 'cover',
format: 'auto',
quality: 85,
},
});const url = KoolbaseStorage.publicUrlWithPreset({
projectId: koolbase.projectId,
presetName: 'avatar',
bucket: 'avatars',
path: 'user_123.png',
});Managing presets
Presets are managed in the Koolbase dashboard. Two ways to create one:
From the transform modal
When previewing a transform on any image in a public bucket, click Save as preset in the modal footer, name it, and the current option set is saved server-side. The new preset is immediately usable in URLs and SDKs.
From the Presets page
Open Storage in the dashboard and click the Presets button. You get a list of every preset in the project with create, edit, and delete actions.
Names are immutable
/p/{project_id}/thumbnail/... breaks the day you rename the preset. The dashboard locks the name field on edit; if you need a different name, create a new preset and delete the old one once nothing references it.Naming rules
Lowercase alphanumeric with _ or -, 1–64 characters, starting with a letter or digit. Names are unique per project.
Caching & pricing
Transformed images are cached at Cloudflare's edge for four hours per unique URL. A request that hits cache costs nothing and serves in milliseconds.
Cloudflare bills unique transformations — each new combination of options against a source image counts once per calendar month, regardless of how many times it's served. The free tier on every Koolbase account includes 5,000 unique transformations per month. Beyond that, $0.50 per 1,000.
What counts as unique
width=400,height=400,format=webp against avatar.png is one unique transformation. The same options against avatar2.png is a second. The same options against avatar.png served 10,000 times is still one.Limits
- Transforms only work on public buckets. Private buckets serve signed URLs that can't be transformed at the edge.
- Source images must be under 20MB and under 100 megapixels (Cloudflare limit).
- Supported source formats: PNG, JPEG, GIF, WebP, AVIF, SVG.
- Output width and height are capped at 2000px each.
Troubleshooting
URL returns the original image, untouched
Confirm the bucket is public. Transforms aren't applied to private buckets — if you need transforms on a private image, copy the file to a public bucket first.
Preset URL returns 404
Double-check the project ID and preset name in the URL. The error response from the edge includes the reason — preset not found, invalid project id, or source not found.
Preset edits don't seem to apply
Edge cache is four hours per unique URL. Edits apply to all new requests immediately, but in-flight cached responses serve their old form until expiry. Append a cache-buster query (?v=2) to force a fresh fetch.
CORS errors in the browser
Make sure your app's origin is in the project's Trusted Origins list.