AVIF Image Format — Better Compression Than WebP and JPEG
AVIF offers 50% smaller files than JPEG at equivalent quality. Learn browser support, how to convert images to AVIF with sharp and ffmpeg, and how to serve AVIF with WebP and...
AVIF is the best image format for web in 2024 by compression ratio. A 1MB JPEG typically becomes 350-500KB WebP and 200-350KB AVIF at equal visual quality.
Compress your images with the Image Compressor.
Format comparison
| Format | Compression | Browser support | Encoding speed |
|---|---|---|---|
| JPEG | Baseline | 100% | Fast |
| WebP | ~30% smaller than JPEG | 97%+ | Fast |
| AVIF | ~50% smaller than JPEG | 92%+ | Slow |
| AVIF (animated) | ~60% smaller than GIF | 92%+ | Very slow |
AVIF browser support (2024): Chrome 85+, Firefox 93+, Safari 16+. IE and older Safari need a fallback.
Convert to AVIF with sharp (Node.js)
import sharp from 'sharp'; // npm install sharp
// Single image conversion:
await sharp('photo.jpg')
.avif({
quality: 65, // 0-100, default 50
effort: 4, // 0-9: speed vs compression tradeoff, default 4
chromaSubsampling: '4:2:0', // default, reduce for quality images
})
.toFile('photo.avif');
// Batch conversion:
import { glob } from 'glob';
import { promises as fs } from 'fs';
const images = await glob('public/images/**/*.{jpg,jpeg,png}');
for (const img of images) {
const avifPath = img.replace(/\.(jpg|jpeg|png)$/, '.avif');
const webpPath = img.replace(/\.(jpg|jpeg|png)$/, '.webp');
await Promise.all([
sharp(img).avif({ quality: 65 }).toFile(avifPath),
sharp(img).webp({ quality: 75 }).toFile(webpPath),
]);
const original = (await fs.stat(img)).size;
const avif = (await fs.stat(avifPath)).size;
console.log(`${img}: ${(original/1024).toFixed(0)}KB → ${(avif/1024).toFixed(0)}KB AVIF`);
}
Convert with ffmpeg (CLI)
# Single image:
ffmpeg -i photo.jpg -c:v libaom-av1 -crf 30 photo.avif
# CRF scale: 0 (lossless) to 63 (worst), ~30 = good quality
# Lower CRF = better quality + larger file
# Batch convert all JPEGs in directory:
for f in *.jpg; do
ffmpeg -i "$f" -c:v libaom-av1 -crf 30 "${f%.jpg}.avif"
done
# With speed control (0=slowest/best, 4=balanced, 8=fastest):
ffmpeg -i photo.jpg -c:v libaom-av1 -crf 30 -cpu-used 4 photo.avif
Serve AVIF with HTML picture element
<!-- Browser picks the first format it supports -->
<picture>
<source srcset="/images/hero.avif" type="image/avif">
<source srcset="/images/hero.webp" type="image/webp">
<img src="/images/hero.jpg" alt="Hero image" width="800" height="450">
</picture>
<!-- With responsive sizes: -->
<picture>
<source
srcset="/images/hero-400.avif 400w, /images/hero-800.avif 800w, /images/hero-1200.avif 1200w"
type="image/avif"
sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
>
<source
srcset="/images/hero-400.webp 400w, /images/hero-800.webp 800w, /images/hero-1200.webp 1200w"
type="image/webp"
sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
>
<img
src="/images/hero-800.jpg"
alt="Hero image"
width="800"
height="450"
loading="lazy"
>
</picture>
nginx: serve AVIF automatically
# Serve AVIF if the browser accepts it and the file exists:
location ~* \.(jpe?g|png)$ {
add_header Vary Accept;
# Try AVIF first:
if ($http_accept ~* "image/avif") {
rewrite ^(.+)\.(jpe?g|png)$ $1.avif break;
}
# Fallback to WebP:
if ($http_accept ~* "image/webp") {
rewrite ^(.+)\.(jpe?g|png)$ $1.webp break;
}
}
A cleaner approach uses map directives — but the picture element in HTML gives browsers explicit control and is more maintainable.
AVIF quality settings guide
// Portrait photography (fine detail, skin tones):
sharp('portrait.jpg').avif({ quality: 70, effort: 6 })
// Product images (clean background, sharp edges):
sharp('product.png').avif({ quality: 75, effort: 4 })
// Hero/background images (large, some blur acceptable):
sharp('hero.jpg').avif({ quality: 55, effort: 4 })
// Thumbnails (small, fast loading more important):
sharp('thumb.jpg').avif({ quality: 60, effort: 2 })
// Lossless (icons, UI elements with text):
sharp('ui-element.png').avif({ lossless: true })
Build pipeline integration
Vite:
// vite.config.js
import viteImagemin from 'vite-plugin-imagemin';
export default {
plugins: [
viteImagemin({
avif: { quality: 65 },
webp: { quality: 75 },
}),
],
};
Next.js (built-in):
// next.config.js — Next.js handles AVIF conversion automatically:
module.exports = {
images: {
formats: ['image/avif', 'image/webp'],
// Next.js serves AVIF to browsers that accept it
},
};
Related tools
- Image Compressor — compress JPEG, PNG, WebP
- Favicon Generator — generate favicons from images
- Base64 Encoder — encode small images as data URIs
Related posts
- Compress JPEG Online — Reduce Image File Size Without Losing Quality — JPEG compression lets you reduce image file sizes by 40–80% with minimal visible…
- Image Compression Formats — JPEG, PNG, WebP, AVIF Compared — JPEG, PNG, WebP, and AVIF compress images differently. JPEG is lossy and best fo…
- Image Compression Guide — Reduce File Size Without Losing Quality — Image compression reduces file size by removing redundant data. Here's how lossy…
- Next.js Image Optimization — next/image Component Guide — The Next.js Image component automatically optimizes images: serving WebP/AVIF, l…
Related tool
Compress JPEG, PNG, and WebP images in your browser. Adjustable quality, batch mode. Files never leave your device.
Written by Mian Ali Khalid. Part of the Frontend & Design pillar.