Astro v6.1.3
Vite v7.3.1
Node v25.8.2
System macOS (x64)
Package Manager npm
Output static
Adapter @astrojs/cloudflare (v13.1.7)
Integrations none
N/A (build-time issue)
When using @astrojs/cloudflare with imageService: { build: "compile" } and a custom image service configured in astro.config.ts, the adapter silently replaces the custom service with its own @astrojs/cloudflare/image-service-workerd. The custom service's getURL() and getHTMLAttributes() methods are never called.
In setImageConfig() (image-config.js), the "compile" case unconditionally overrides the image service:
case "compile":
return {
...config,
service: WORKERD_IMAGE_SERVICE, // always overrides user's service
endpoint: ...
};Additionally, in prerenderer.js, collectStaticImages hardcodes astro/assets/services/sharp for build-time image transforms:
const { default: sharpService } = await import("astro/assets/services/sharp");
globalThis.astroAsset.imageService = sharpService;This means there is no way to use a custom image transform pipeline (e.g. an external image CDN or optimization service) with build: "compile".
This repo has a custom image service at src/image-service.ts that returns /cdn/-prefixed URLs and adds a data-image-service="custom" attribute. Neither appears in the build output.
The config:
export default defineConfig({
output: "static",
adapter: cloudflare({
imageService: { build: "compile" },
}),
image: {
service: {
entrypoint: "./src/image-service.ts",
},
},
});Run npm run build and inspect dist/client/index.html.
The custom image service should be used for URL generation and HTML attributes. The rendered HTML should contain:
<img src="/cdn/..." data-image-service="custom" alt="test" width="100" height="100">The "compile" case in setImageConfig should respect the user's image.service configuration instead of unconditionally replacing it. If the user has configured a custom service, it should be used for getURL() and getHTMLAttributes() — the adapter should only fall back to @astrojs/cloudflare/image-service-workerd when no custom service is set.
Similarly, collectStaticImages in prerenderer.js should check whether a custom image service is configured before defaulting to sharp. A "custom" build service option (or detecting that image.service was explicitly set) could skip the sharp override and let the user's transform logic handle image generation.
https://github.com/adamchal/cloudflare-custom-image
- I am willing to submit a pull request for this issue.