Images are usually the heaviest part of a WordPress page, and the most common cause of a slow Largest Contentful Paint (LCP). Optimizing them means four things: the right dimensions, the right format, good compression, and smart loading. Most of it can be automated on your server.

1. Upload sensible dimensions

A 6000-pixel photo straight from a camera is useless on a 1200-pixel-wide content column.

  • WordPress (5.3+) automatically scales down uploads larger than 2560 pixels (the “big image threshold”). You can lower it:
// in a small plugin or the theme's functions.php
add_filter( 'big_image_size_threshold', fn() => 1920 );
  • WordPress generates several sizes (thumbnail, medium, medium_large, large, plus theme sizes) and outputs srcset and sizes, so browsers download the smallest suitable file. Make sure your theme uses wp_get_attachment_image() or the block editor, so this works.
  • Remove image sizes you never use (themes and plugins add many), to save disk space and processing time.

2. Use modern formats: WebP and AVIF

Format Typical size vs JPEG Browser support
JPEG/PNG baseline universal
WebP 25–35% smaller all modern browsers
AVIF 40–50% smaller all modern browsers (slower to encode)
  • WordPress core supports uploading WebP and AVIF (AVIF since 6.5), if your server’s image library supports them.
  • Check your server: Tools → Site Health → Info → Media Handling shows whether ImageMagick or GD can write WebP and AVIF. Install php-imagick with a recent ImageMagick if needed. See PHP extensions.
  • Core can generate WebP sub-sizes for JPEG uploads with the image_editor_output_format filter:
add_filter( 'image_editor_output_format', function ( $formats ) {
    $formats['image/jpeg'] = 'image/webp';
    return $formats;
} );

3. Compress

  • Plugins: ShortPixel, Imagify, EWWW Image Optimizer, Optimole, and others compress images, convert them to WebP/AVIF, and can bulk-optimize your existing library. Some process images on their servers (using your quota), and some locally on your VPS.
  • Local tools on your VPS (free, no quotas):
sudo apt install -y jpegoptim optipng webp
# lossy JPEG to quality 82, strip metadata
find /var/www/example.com/wp-content/uploads -name '*.jpg' -size +200k -exec jpegoptim --max=82 --strip-all {} \;
# make WebP copies
find /var/www/example.com/wp-content/uploads -name '*.jpg' -exec sh -c 'cwebp -q 80 "$1" -o "${1%.*}.webp"' _ {} \;

Back up the uploads folder before bulk changes. See backup strategy.

Serving the .webp copies: a plugin can rewrite URLs, or Nginx can serve WebP automatically when the browser accepts it:

map $http_accept $webp_suffix {
    default "";
    "~*webp" ".webp";
}
location ~* ^/wp-content/uploads/.+\.(png|jpe?g)$ {
    add_header Vary Accept;
    try_files $uri$webp_suffix $uri =404;
    expires 30d;
}

(This expects WebP files named image.jpg.webp. Adjust it to match your naming.)

4. Load images smartly

  • Lazy-load below-the-fold images. WordPress adds loading="lazy" automatically. See WordPress lazy loading.
  • Don’t lazy-load the LCP image (usually the hero or featured image). WordPress tries to skip the first content image, and adds fetchpriority="high". Check with PageSpeed Insights.
  • Always output width and height attributes (WordPress does), so the layout doesn’t shift (CLS).

5. Deliver from a CDN

A CDN serves images from servers near visitors. Some image CDNs (Cloudflare Images, BunnyCDN Optimizer, Optimole) also resize and convert on the fly. See WordPress CDN setup.

6. Cache headers

Images don’t change once uploaded, so cache them for a long time:

location ~* \.(jpg|jpeg|png|gif|webp|avif|svg)$ {
    expires 30d;
    access_log off;
}

See Nginx static file caching.

Measure

  • PageSpeed Insights / Lighthouse: “Properly size images”, “Serve images in next-gen formats”, “Largest Contentful Paint element”.
  • Before and after: check total page weight in your browser’s DevTools (Network tab, filter by Img).

See Core Web Vitals and server performance.

Quick reference

Goal How
Smaller dimensions big_image_size_threshold, responsive srcset
Modern formats WebP/AVIF via Imagick, plugin, or cwebp
Compression ShortPixel/Imagify/EWWW, or jpegoptim
Loading lazy-load below the fold; fetchpriority="high" for LCP
Delivery CDN + long cache headers

Related: WordPress performance tuning and WordPress VPS hosting.

  • WordPress
  • Performance
  • Images