Astro shows “getImage() must be used on the server” when getImage() from astro:assets runs in the browser, for example inside a React island or a <script> tag. Image processing happens at build time (or on the server), not in the visitor’s browser. The message gives the fix: “render the src from getImage() during the server render, then pass it to the client for usage.”
Key Takeaways
- Call
getImage()in.astrofrontmatter or other server code only.- Pass the result (
src,srcSet,attributes) to islands as props or to scripts asdata-*attributes.- Framework components that import
astro:assetsand run with aclient:*directive will hit this.- For many images, process them all on the server and pass an array of URLs.
Wrong: getImage in an island
// src/components/Gallery.tsx (rendered with client:visible)
import { getImage } from 'astro:assets';
import photo from '../assets/photo.jpg';
export default function Gallery() {
const img = await getImage({ src: photo, width: 800 }); // runs in the browser
return <img src={img.src} alt="" />;
}
Right: process on the server, pass the result
---
// src/pages/gallery.astro
import { getImage } from 'astro:assets';
import Gallery from '../components/Gallery.tsx';
import one from '../assets/one.jpg';
import two from '../assets/two.jpg';
const images = await Promise.all(
[one, two].map(async (src) => {
const img = await getImage({ src, width: 800, format: 'webp' });
return { src: img.src, width: img.attributes.width, height: img.attributes.height };
}),
);
---
<Gallery client:visible images={images} />
// src/components/Gallery.tsx
type Img = { src: string; width: number; height: number };
export default function Gallery({ images }: { images: Img[] }) {
return images.map((img) => (
<img src={img.src} width={img.width} height={img.height} alt="" loading="lazy" />
));
}
The island receives plain strings and numbers, which serialise cleanly into the page.
For a script tag
Put processed URLs in data attributes:
---
import { getImage } from 'astro:assets';
import large from '../assets/large.jpg';
const full = await getImage({ src: large, width: 2000 });
---
<button class="zoom" data-full={full.src}>View full size</button>
<script>
document.querySelector<HTMLButtonElement>('.zoom')?.addEventListener('click', (e) => {
const url = (e.currentTarget as HTMLElement).dataset.full!;
window.open(url, '_blank');
});
</script>
Using an image as a CSS background
Same pattern: call getImage() in frontmatter and pass the URL to CSS with define:vars. The define:vars tip shows it.
For island props and serialisation rules, see the Astro components guide. Image options are covered in the Astro performance guide, and the getImage() reference lists every option.
FAQ
Can I use the Image component inside a React component?
No. <Image /> is an Astro component. Process the image in the Astro file and pass the URL into the React component as a prop.
Does getImage() work in endpoints?
Yes. Endpoints run on the server (or at build time), so getImage() works there, for example when generating Open Graph images.