⚛️ React & Next.js Guide
WebP for React & Next.js
Next.js converts images to WebP automatically via next/image. Plain React needs a manual approach — the <picture> element or a build-time tool. Full implementation guide with code examples.
Free WebP converter
No upload, no account
Batch convert entire /public folder
Code examples included
Convert JPG/PNG to WebP for Your Project
For images outside next/image, convert locally — free and instant.
Convert to WebP →
Next.js vs Plain React — Which Approach You Need
| Feature | Next.js (next/image) | Plain React (CRA / Vite) |
| Auto WebP conversion | ✓ Automatic | ✗ Manual or build tool |
| Responsive srcset | ✓ Automatic | Manual <picture> or plugin |
| Lazy loading | ✓ Default | Add loading="lazy" |
| LCP optimization | priority prop | Manual preload link |
| Blur placeholder | ✓ placeholder="blur" | ✗ Manual CSS |
| Manual pre-conversion needed | No | Yes, for <picture> approach |
Next.js — Using next/image (Recommended)
If you're using Next.js, next/image handles WebP conversion, responsive srcset, and lazy loading automatically. You just point it at your original JPG or PNG:
Basic usage
import Image from 'next/image'
// Next.js serves WebP to supporting browsers automatically
<Image
src="/images/hero.jpg"
alt="Your hero description"
width={1600}
height={900}
priority {/* ← add this for the LCP/hero image */}
/>
With responsive fill (covers parent container)
// next.config.js — configure image domains if using remote URLs
module.exports = {
images: {
remotePatterns: [
{ protocol: 'https', hostname: 'your-cdn.com' }
],
formats: ['image/avif', 'image/webp'], // serve AVIF then WebP
}
}
// In your component
<div style={{ position: 'relative', width: '100%', height: '400px' }}>
<Image
src="/images/hero.jpg"
alt="Hero image"
fill
style={{ objectFit: 'cover' }}
priority
/>
</div>
When next/image doesn't apply: CSS background images, Open Graph images (og:image), images served from the /public folder via direct URL, and images in email templates. For these, convert to WebP manually using Convertlo.
Plain React — Three Approaches
Recommended
<picture> element
Manual WebP + JPG fallback. Works everywhere, no build config needed. Best for a small number of images.
Build tool
vite-imagetools (Vite)
Auto-convert at build time via import query. Best for Vite projects with many images.
Build tool
imagemin-webp-webpack
Webpack / CRA plugin. Generates .webp files alongside originals at build time.
Approach 1 — <picture> element (manual WebP + fallback)
{/* First: convert hero.jpg → hero.webp using Convertlo */}
{/* Then use both in your component */}
function HeroImage() {
return (
<picture>
<source srcSet="/images/hero.webp" type="image/webp" />
<img
src="/images/hero.jpg"
alt="Hero description"
width={1600}
height={900}
fetchPriority="high" {/* for LCP element */}
style={{ width: '100%', height: 'auto' }}
/>
</picture>
)
}
Approach 2 — vite-imagetools (Vite projects)
# Install
npm install vite-imagetools --save-dev
# vite.config.ts
import { imagetools } from 'vite-imagetools'
export default { plugins: [imagetools()] }
# In your component — auto-converts at build time
import heroWebp from './hero.jpg?format=webp'
import heroJpg from './hero.jpg'
<picture>
<source srcSet={heroWebp} type="image/webp" />
<img src={heroJpg} alt="Hero" width={1600} height={900} />
</picture>
Approach 3 — Reusable WebP component
// components/WebPImage.tsx
interface Props {
src: string // path without extension, e.g. "/images/hero"
alt: string
width: number
height: number
priority?: boolean
className?: string
}
export function WebPImage({ src, alt, width, height, priority, className }: Props) {
return (
<picture>
<source srcSet={`${src}.webp`} type="image/webp" />
<img
src={`${src}.jpg`}
alt={alt}
width={width}
height={height}
loading={priority ? 'eager' : 'lazy'}
fetchPriority={priority ? 'high' : 'auto'}
className={className}
/>
</picture>
)
}
// Usage — assumes both hero.webp and hero.jpg exist in /public/images
<WebPImage src="/images/hero" alt="Hero" width={1600} height={900} priority />
WebP for CSS Background Images in React
CSS background-image doesn't use the <picture> element. Serve WebP directly and let the browser handle it — WebP is supported by 97%+ of browsers:
/* CSS — use WebP directly for background images */
.hero {
background-image: url('/images/hero.webp');
background-size: cover;
}
/* If you need a JPG fallback for older browsers */
.hero {
background-image: url('/images/hero.jpg'); /* fallback first */
}
@supports (background-image: url('x.webp')) {
.hero {
background-image: url('/images/hero.webp');
}
}
For CSS background images in React/Next.js components, just convert to WebP using Convertlo and reference the .webp file directly. The @supports fallback is optional — fewer than 3% of users lack WebP support.
React & Next.js Image Performance Tips
Next.js priority
Add priority to your hero Image
The priority prop on next/image adds a preload link and disables lazy loading. Add it to the first above-the-fold image — the one that is the LCP element. Missing this is the most common Next.js LCP mistake.
Dimensions
Always specify width and height
Both next/image and plain <img> need explicit width and height to prevent CLS (Cumulative Layout Shift). Without them, the browser can't reserve space — content jumps as images load.
og:image
Keep og:image as JPG even in Next.js
Your og:image meta tag URL should point to a JPG. Social media crawlers (LinkedIn, Slack, Twitter) sometimes mishandle WebP og:image. Keep the og:image as JPG; use WebP for page content images.
Formats config
Enable AVIF in next.config for cutting-edge compression
Add formats: ['image/avif', 'image/webp'] in next.config images settings. Next.js will serve AVIF (even smaller than WebP) to Chrome 85+, WebP to other supporting browsers, and JPG as fallback.
Sizes prop
Use the sizes prop for responsive images
sizes="(max-width: 768px) 100vw, 50vw" tells Next.js how large the image appears at each breakpoint — so it generates the right srcset entries. Without it, Next.js generates all sizes unnecessarily.
public/ folder
Images in /public bypass next/image optimization
Files in the /public folder served at their direct URL (e.g. /logo.png) are NOT converted by next/image. Pre-convert these to WebP manually using Convertlo.
Frequently Asked Questions
Does Next.js automatically convert images to WebP?
Yes, via the next/image component. It converts JPG and PNG to WebP for supporting browsers, generates responsive srcsets, and lazy loads by default. You provide the original image — Next.js handles WebP delivery via /_next/image. Images in /public served directly as static files bypass this optimization.
How do I use WebP in a React app without Next.js?
Manual approach: Convert your JPG/PNG to WebP using Convertlo. Use the <picture> element with a WebP source and JPG fallback. Build tool approach: Use vite-imagetools (Vite) or imagemin-webp-webpack-plugin (Webpack/CRA) for automatic build-time conversion. The <picture> approach is simplest for a few images; build tools scale better for large projects.
Should I use next/image or a regular img tag?
Always next/image for content images — it provides automatic WebP, lazy loading, blur placeholder, and the priority prop for LCP optimization. Use a regular img (or <picture>) for images in CSS backgrounds, email templates, og:image references, or images served directly from /public as static assets.
Do I need to pre-convert images to WebP in a Next.js project?
For images used via next/image — no. Next.js converts at request time and caches the result. But you should pre-convert images that are: (1) in /public served directly by URL, (2) used as CSS background-image, (3) referenced in og:image meta tags (though keep og:image as JPG for crawler compatibility), (4) used in non-Next.js parts of your stack.
How do I use WebP for CSS background images in React?
Convert your image to WebP using Convertlo, then reference it directly in CSS: background-image: url('/hero.webp'). WebP is supported by 97%+ of browsers — a JPG fallback via @supports is optional. For critical above-the-fold background images, add a preload link: <link rel="preload" as="image" href="/hero.webp"> to avoid render-blocking.