Posted on: 04/09/2026(updated)
In RSC (Next.js), using next/image optimises your image automatically, and it works server-side by default since it's not a client component.
import Image from 'next/image'
export default function Page() {
return (
<Image src="/hero.jpg" alt="Hero"
width={1200}
height={600}
priority
/>
)
}
What it gives you automatically:
srcset from width/height (or fill)preload manually with priorityFor truly static/known-at-build images you can import the file directly and skip specifying width/height --Next.js infers them:
import hero from './hero.jpg'
<Image src={hero} alt="Hero" priority />
If it's a remote image, add the domain to images.remotePatterns in next.config.js.
Only reach for manual preload() if you're not using next/image or need a hint for something next/image doesn't cover (e.g. a CSS background image).
In React there's no next/image automations. Plain React gives you the <img> tag and the preload/preinit hints, nothing else. You're responsible for:
vite-imagemin, sharp in a build script) or use an image CDN (Cloudinary, Cloudflare Images, imgix) that transforms on the fly via URL params.srcset/sizes — write manually:<img
src="/hero-800.jpg"
srcSet="/hero-400.jpg 400w, /hero-800.jpg 800w,
/hero-1200.jpg 1200w"
sizes="(max-width: 600px) 400px, 800px"
alt="Hero"
width={1200}
height={600}
/>
loading="lazy" attribute (or loading="eager" for above-fold).width/height (or aspect-ratio in CSS).preload() from react-dom comes in, for your above-fold/LCP image:import { preload } from 'react-dom'
preload('/hero-800.jpg', {
as: 'image',
imageSrcSet: '...',
imageSizes: '...'
})
So the pieces next/image bundles for you (format conversion, resizing, srcset generation, priority preload) become separate manual steps or a third-party service in plain React.