- Manage hosted images with Workers·续
- List images with pagination
- Get the details for a single image
- Stream the original bytes for an image
- Update image metadata
- Delete an image
- Generate a signed URL for a private image
- Create a Direct Creator Upload URL
- Ingest a remote image into Images storage
- Type definitions
- Error handling
- Local development
- Related resources
- On this page
Manage hosted images with Workers·续
return Response.json(image); }, };
```ts
export default {
async fetch(request, env) {
if (!request.body) {
return new Response("Missing body", { status: 400 });
}
const image = await env.IMAGES.hosted.upload(request.body, {
encoding: "base64",
filename: "upload.png",
});
return Response.json(image);
},
};
List images with pagination
export default {
async fetch(request, env) {
let cursor;
const ids = [];
do {
const page = await env.IMAGES.hosted.list({ limit: 100, cursor });
ids.push(...page.images.map((image) => image.id));
cursor = page.cursor;
} while (cursor);
return Response.json({ count: ids.length, ids });
},
};
export default {
async fetch(request, env) {
let cursor: string | undefined;
const ids: string[] = [];
do {
const page = await env.IMAGES.hosted.list({ limit: 100, cursor });
ids.push(...page.images.map((image) => image.id));
cursor = page.cursor;
} while (cursor);
return Response.json({ count: ids.length, ids });
},
};
Get the details for a single image
export default {
async fetch(request, env) {
const details = await env.IMAGES.hosted.image("IMAGE_ID").details();
if (!details) {
return new Response("Not found", { status: 404 });
}
return Response.json(details);
},
};
export default {
async fetch(request, env) {
const details = await env.IMAGES.hosted.image("IMAGE_ID").details();
if (!details) {
return new Response("Not found", { status: 404 });
}
return Response.json(details);
},
};
Stream the original bytes for an image
export default {
async fetch(request, env) {
const bytes = await env.IMAGES.hosted.image("IMAGE_ID").bytes();
if (!bytes) {
return new Response("Not found", { status: 404 });
}
return new Response(bytes);
},
};
export default {
async fetch(request, env) {
const bytes = await env.IMAGES.hosted.image("IMAGE_ID").bytes();
if (!bytes) {
return new Response("Not found", { status: 404 });
}
return new Response(bytes);
},
};
Update image metadata
export default {
async fetch(request, env) {
const updated = await env.IMAGES.hosted.image("IMAGE_ID").update({
metadata: { reviewed: true },
});
return Response.json(updated);
},
};
export default {
async fetch(request, env) {
const updated = await env.IMAGES.hosted.image("IMAGE_ID").update({
metadata: { reviewed: true },
});
return Response.json(updated);
},
};
Delete an image
export default {
async fetch(request, env) {
const deleted = await env.IMAGES.hosted.image("IMAGE_ID").delete();
return new Response(deleted ? "Deleted" : "Not found", {
status: deleted ? 200 : 404,
});
},
};
export default {
async fetch(request, env) {
const deleted = await env.IMAGES.hosted.image("IMAGE_ID").delete();
return new Response(deleted ? "Deleted" : "Not found", {
status: deleted ? 200 : 404,
});
},
};
Generate a signed URL for a private image
Redirect the browser to a short-lived signed URL so it can fetch a private image directly without streaming the bytes through your Worker.
export default {
async fetch(request, env) {
const url = await env.IMAGES.hosted.image("IMAGE_ID").signedUrl({
variant: "private",
expiresIn: 86_400,
});
return Response.redirect(url, 302);
},
};
export default {
async fetch(request, env) {
const url = await env.IMAGES.hosted.image("IMAGE_ID").signedUrl({
variant: "private",
expiresIn: 86_400,
});
return Response.redirect(url, 302);
},
};
Create a Direct Creator Upload URL
Create a one-time upload URL and return it to a client, which can then upload an image straight to Cloudflare without your Worker handling the bytes or an API token.
export default {
async fetch(request, env) {
const { id, uploadURL } = await env.IMAGES.hosted.createDirectUpload({
metadata: { userId: "abc123" },
requireSignedURLs: true,
expiresIn: 600,
});
return Response.json({ id, uploadURL });
},
};
export default {
async fetch(request, env) {
const { id, uploadURL } = await env.IMAGES.hosted.createDirectUpload({
metadata: { userId: "abc123" },
requireSignedURLs: true,
expiresIn: 600,
});
return Response.json({ id, uploadURL });
},
};
Ingest a remote image into Images storage
This example fetches an image from a remote URL, uploads it into your Images account, and returns the first variant URL.
export default {
async fetch(request, env) {
const upstream = await fetch("https://example.com/photo.jpg");
if (!upstream.ok || !upstream.body) {
return new Response("Upstream fetch failed", { status: 502 });
}
const image = await env.IMAGES.hosted.upload(upstream.body, {
filename: "photo.jpg",
metadata: { source: "example.com" },
});
return Response.json({
id: image.id,
variant: image.variants[0],
});
},
};
export default {
async fetch(request, env) {
const upstream = await fetch("https://example.com/photo.jpg");
if (!upstream.ok || !upstream.body) {
return new Response("Upstream fetch failed", { status: 502 });
}
const image = await env.IMAGES.hosted.upload(upstream.body, {
filename: "photo.jpg",
metadata: { source: "example.com" },
});
return Response.json({
id: image.id,
variant: image.variants[0],
});
},
};
Type definitions
ImageMetadata
Returned by operations that retrieve, create, or update an image.
idstring- The unique identifier for the image.
filenamestringoptional- The original filename supplied at upload time.
uploadedstringoptional- The date and time the image was uploaded, as an ISO 8601 string.
requireSignedURLsboolean- Whether signed URLs are required to access this image. Refer to Serve private images.
metaRecord<string, unknown>optional- User-supplied metadata associated with the image.
variantsArray<string>- Fully-formed URLs for each variant configured on your account. Refer to Create variants.
draftbooleanoptional- Whether the image is in a draft state (no bytes uploaded yet). Drafts are typically only seen on accounts using Direct Creator Uploads.
creatorstringoptional- A user-defined identifier for the image creator.
ImageList
Returned by list().
imagesArray<ImageMetadata>- The images in this page of results.
cursorstringoptional- A continuation token to pass to the next
list()call. Only present when there are more results. listCompletebooleantruewhen there are no further pages,falseotherwise.
DirectUploadResult
Returned by createDirectUpload().
idstring- The ID that the uploaded image will have.
uploadURLstring- The one-time URL that a client uploads the image bytes to.
Error handling
Methods that fail throw an ImagesError — .upload(), .list(), .createDirectUpload(), .update(), and .signedUrl() — with the following properties:
codenumber- A numeric error code that identifies the failure mode.
messagestring- A human-readable description of the error.
Methods that fetch a single image — .details(), .bytes(), and .delete() — return null or false for "not found" rather than throwing.
You may want to wrap operations that can throw in a try...catch block.
Local development
When you run wrangler dev, operations for managing hosted images are served by a local mock that stores images in an embedded KV namespace. The mock supports every method documented on this page, so you can develop and test your Worker offline.
The mock is only suitable for local development. To exercise the real Images service from your local environment, run wrangler dev --remote.
Related resources
- Optimize with Workers — Use the binding to optimize images from a Worker.
- Upload via the REST API — The equivalent HTTP API.
- Manage hosted images — Dashboard and API workflows for managing stored images.
Was this helpful?
YesNo
On this page
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/images/storage/binding/#page","headline":"Manage hosted images with Workers","description":"Use the Images binding to upload, list, retrieve, update, and delete hosted images from a Worker.","url":"https://developers.cloudflare.com/images/storage/binding/","inLanguage":"en","image":"https://developers.cloudflare.com/images/storage/binding/og.png?v=5aa2b6e200e33867","dateModified":"2026-09-02","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
description: Remove images from Cloudflare Images storage using the dashboard or API. title: Delete images image: https://developers.cloudflare.com/images/storage/manage-images/delete-images/og.png?v=f81f630393ab85a8
Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/images/llms.txt
Use this file to discover all available pages before exploring further.
Docs