WordPress Images

WordPress Image Sizes Explained: Every File Created From a Single Upload

One upload becomes eight or more files. Here is what WordPress actually creates, why some sizes are missing, and what to do about it, with numbers measured on a real site.

WordPress Image Sizes Explained: Every File Created From a Single Upload

You drag one photograph into the Media Library. WordPress tells you the upload succeeded and shows you a thumbnail. It looks like one file arrived and one file is now stored.

That is not what happened. Somewhere between the drop and the confirmation, WordPress opened your photograph, resized it seven times, wrote seven new files to disk, and recorded all of them in a database row you will probably never look at. The original is still there too, untouched, and on most sites it will never be sent to a visitor again.

None of this is a bug. It is the mechanism that lets a phone on a slow connection and a 27-inch monitor load the same page and each get a file that suits them. But it is invisible, it compounds, and it explains a whole family of problems that look unrelated: images that are inexplicably soft in one place and sharp in another, a media folder that has quietly grown to twelve gigabytes, a plugin that suddenly shows blurry product thumbnails for old items and perfect ones for new items.

This article is about what actually gets created, why some of it is missing, and what to do about it.

Scale diagram of the eight files WordPress creates from one 4000 by 3000 pixel upload, from the 5.2 MB original down to the 150 pixel thumbnail

The sizes WordPress creates without being asked

A clean WordPress install with no theme and no plugins registers five image sizes. Three of them are visible in Settings → Media. Two are not, which is the first place people lose track.

thumbnail: 150 × 150, cropped. The only default size that crops. Everything else scales proportionally; the thumbnail is forced into a square, and WordPress decides which part of your picture survives. If your subject is off-centre, this is where it gets beheaded.

medium: 300 px on the longest side. Scaled, not cropped.

medium_large: 768 px wide. This one has no setting in the admin at all. It was added in WordPress 4.4 to feed responsive images, and it exists on your site whether or not you want it.

large: 1024 px on the longest side.

1536×1536 and 2048×2048. Added in WordPress 5.3, again with no admin setting, again for high-density screens. These are the retina counterparts of medium_large and large.

That is seven files, not counting your original. And there is an eighth thing that happens to large uploads, which is the part that confuses people most.

The original you can no longer reach

Since WordPress 5.3, any image wider or taller than 2560 pixels gets a new file appended with -scaled in the name. Upload beach.jpg at 4000 × 3000 and you get beach-scaled.jpg at 2560 × 1920.

From that moment, beach-scaled.jpg is what WordPress treats as the image. It is what the editor inserts, what other sizes are derived from, what the REST API returns. Your 4000-pixel original is still on disk under its original name, but nothing links to it. It sits there being 5 MB.

This is not a rare edge case. The first diagram in this article was uploaded at 1800 × 3320 pixels, and the version you are looking at is -scaled, resized to 2560 on the long edge, because the threshold applies to height just as it does to width.

The threshold is a filter, big_image_size_threshold, and you can raise it, lower it, or switch it off entirely by returning false. Switching it off is tempting and usually wrong: it means every page that inserts a full-size image is handing visitors a multi-megabyte file. Raising it to 3000 or 3500 is the reasonable move if you publish photography and want more detail available.

Why half your sizes are missing

Here is the rule that explains more confusion than any other: WordPress never scales an image up.

A size is only created if the original is larger than the target. Upload a 900-pixel-wide image and you get thumbnail, medium and medium_large. You do not get large, you do not get 1536, you do not get 2048, not as empty files, not as copies, not at all. The database simply has no entry for them.

This has a consequence people run into constantly. When a template asks for the large size and large does not exist for that image, WordPress falls back to the full file. Sometimes that is fine. Sometimes the full file is 300 pixels wide and gets stretched across a 1200-pixel-wide card, and you spend an afternoon convinced your theme is broken.

Matrix showing which image sizes WordPress creates for uploads from 800 to 4000 pixels wide, demonstrating that sizes larger than the original are never generated

What themes and plugins add on top

Everything above is core. Almost no real site runs only core.

Any theme or plugin can register its own sizes with add_image_size(), and they do it liberally. A theme with a hero area, a blog grid, a related-posts strip and a gallery might register six. WooCommerce registers three of its own: a product thumbnail, a single-product image and a gallery thumbnail. Email plugins register one for newsletter width. Page builders register their own.

They stack. Nothing consolidates them, nothing notices that two plugins have registered near-identical dimensions, and there is no admin screen listing them.

To see what your site actually registers, this returns the full list including everything themes and plugins have added:

print_r( wp_get_registered_image_subsizes() );

And to see what actually exists for one specific attachment, which is a different question, because of the no-upscaling rule:

print_r( wp_get_attachment_metadata( 1234 ) );

The second one is the honest answer. The first tells you what your site would like to create; the second tells you what it managed to create for that particular file.

What this looks like on a real site

The numbers below come from this website, counted directly in the database rather than estimated.

The Media Library holds 634 images. Those 634 uploads have produced 3,765 files.

The distribution is uneven, and the unevenness is the interesting part. Only 30 images have a 2048-pixel version, because only 30 uploads were ever that large: that is the no-upscaling rule, visible in production. Meanwhile thumbnail and medium exist for almost everything, and the sizes in between fall away steadily as originals get smaller.

The WooCommerce row is the one worth pausing on. WooCommerce registers its three sizes, but registration only affects uploads that happen afterwards. The images that were already in the library when it was activated never got them, and never will, until someone regenerates. On a shop, that is exactly the situation where half the product thumbnails look right and half look soft, and the pattern follows upload date, which is why it seems random.

Bar chart of a real media library where 634 uploaded images produced 3,765 files, with only 30 images large enough for the 2048 pixel size

Which file a visitor actually receives

Having all these sizes would be pointless if the browser could not choose between them. That is what the srcset attribute is for: WordPress lists the available widths, the browser picks one based on the viewport and the screen density, and the file that arrives is usually neither the largest nor the smallest.

The mechanism has its own set of traps, particularly the sizes attribute, which is the part that actually determines whether a browser makes a good choice or a wasteful one. That is a subject of its own, and it is covered in why your images look soft on a retina screen.

For the purposes of this article, one number matters: of the eight or more files sitting on disk for a given image, a single visitor loads at most two: one for the layout, occasionally a second if the layout changes on resize. Everything else is storage.

Reading the list is one thing, watching it happen to your own file is another. Drop an image below, add the sizes your theme registers, and the simulator writes out every file WordPress would create from that one upload, with dimensions, crop behaviour and a size estimate for each.

Upload simulator

Drop one image and see what a WordPress install would really do with it: whether it gets a -scaled copy, which sub-sizes are actually written, what each one costs in bytes, the srcset a browser receives and the file names on disk. Every pixel is decoded and re-encoded in this browser tab, nothing is uploaded anywhere.

Drop one image here or press Enter to pick a file. JPEG, PNG, WebP or GIF.

No image yet. Everything below starts at WordPress core's own defaults and can be edited.

Registered sizes
Name Width Height Crop Remove

A height of 0 means no limit, the way core registers medium_large as 768 by 0. With crop off a size is a bounding box, with crop on it is exact, cut from the position you pick.

Paste the add_image_size() lines from functions.php
Install settings

82 and 86 are core's own defaults, one per format. A threshold of 0 switches the big image scaling off, which is what big_image_size_threshold returning false does.

No image yet

Nothing simulated yet. Drop an image above, or press Try a sample photo to watch a 3000 by 2000 pixel upload go through it.

WunderPaint
The Dynamic Design and Automation Studio
WunderPaint is a layered image editor for your WordPress media library. WunderPaint Studio is the same thing in any browser, free and without an account.

Changing what gets created

Three things are worth doing, in increasing order of impact.

Set the three visible sizes deliberately. Settings → Media. Most people never touch these and end up with sizes that match nothing in their design. If your content column is 720 pixels wide, a 1024-pixel large is sensible and a 300-pixel medium is probably useless to you.

Remove sizes you do not use. This goes in your theme’s functions.php or a small plugin:

add_action( 'init', function () {
    remove_image_size( 'woocommerce_gallery_thumbnail' );
    remove_image_size( '2048x2048' );
} );

Be careful here. Removing a size a template still asks for means that template falls back to the full file. Check before you remove, not after.

Add sizes that match your actual layout.

add_action( 'after_setup_theme', function () {
    add_image_size( 'card', 640, 400, true );   // true = hard crop
} );

The fourth argument is the crop flag. true forces the exact dimensions and discards what does not fit; false scales to fit within the box. For cards and grids where everything must align, you want the crop.

A note on cropping: WordPress decides which part of the image survives, and its default is the centre. For product shots and portraits that is often wrong, and the fix is not code: it is cropping the image deliberately before it ever reaches the Media Library.

Regenerating after a change

None of the above affects images already uploaded. Registration is forward-looking. After changing sizes you either regenerate or live with a library where old and new images behave differently, which, as the WooCommerce numbers above show, is a real and confusing state to be in.

Regenerating means WordPress re-opens every original and re-derives every registered size. The word “re-opens” is doing a lot of work in that sentence, and it is where the problems come from.

Memory is the constraint, not disk or CPU. A JPEG is compressed on disk and uncompressed in memory. A 4000 × 3000 photograph is perhaps 5 MB as a file and roughly 48 MB once PHP has it open as a bitmap: four bytes per pixel, twelve million pixels. During a resize, the source and the target are both in memory at once. A PHP memory limit of 128 MB handles that, but it does not handle it comfortably, and a 6000-pixel original will kill the process outright. The symptom is a regeneration that stops partway with no useful error, or a white screen.

Before starting anything on a large library, check what you actually have:

echo ini_get( 'memory_limit' );   // PHP's ceiling
echo WP_MEMORY_LIMIT;             // what WordPress asks for

256 MB is a sensible working figure. If your host caps you lower and will not move, the answer is not to force it: it is to reduce the size of the originals first.

Do it in the right order. Regenerating is the expensive step, so everything that reduces work should happen before it, not after: delete images you do not need at all; remove sizes you do not use with remove_image_size(), so you are not faithfully recreating three shop sizes on 600 images that will never appear in a shop; decide on big_image_size_threshold now, because changing it afterwards means regenerating again. Then regenerate.

Doing this in the reverse order is the common mistake, and it turns a five-minute job into two five-minute jobs plus a lot of files you then delete.

Expect it to take longer than you think. A few hundred images is a couple of minutes. Ten thousand is not ten times longer: it is longer than that, because larger libraries tend to contain larger originals. Run it from WP-CLI if you have shell access, because a browser tab that times out mid-run leaves you with a partially regenerated library and no record of where it stopped:

wp media regenerate --yes
wp media regenerate --only-missing --yes   # skips what already exists

The --only-missing flag is the one to reach for when you have added a size rather than changed one. It skips every attachment that already has all its registered sizes, which on a library like the one measured above means it touches roughly half the images instead of all of them.

One thing regenerating cannot fix. If your original was too small to begin with, no amount of regeneration creates the missing large sizes: the no-upscaling rule still applies. Those images need to be re-uploaded at a higher resolution or left alone. Regeneration is not a repair tool; it only re-derives what the original can support.

This is also the moment to ask whether you want to regenerate everything at all. If the library has never been audited, there is usually more to clean up than sizes alone: orphaned files with no attachment record, duplicates uploaded three times under slightly different names, and sizes belonging to plugins that were removed years ago and never cleaned up after themselves.

When something looks wrong: symptoms and causes

Most of the questions people ask about image sizes do not arrive as questions about image sizes. They arrive as a specific thing looking wrong. Here are the common ones and what is usually behind them.

An image is sharp in the post but soft in the archive listing, or the other way round. The two places request different sizes. One of them is requesting a size that does not exist for that image, and WordPress is falling back to whatever is available: often the full file, scaled down by CSS, or a small size stretched up. Check wp_get_attachment_metadata() for that specific attachment and see which sizes are actually there.

Product thumbnails look right for new items and soft for old ones. Classic registration-order problem. The theme or plugin registered its sizes after those older images were uploaded, so the sizes were never created for them. Regenerate with --only-missing.

A picture is beheaded, or the wrong part of it is showing. That is the hard crop, and WordPress chose the centre. Either register that size with false as the crop argument so it scales instead, or crop the image deliberately before uploading. There is no setting for “crop toward the top”.

The Media Library is enormous and you cannot account for it. Multiply your upload count by the number of registered sizes and you usually have your answer before you look at anything else. Then check for a -scaled situation: every large upload is storing both a full original nothing links to and a 2560 working copy.

A newly uploaded image looks worse than the file you uploaded. WordPress re-encodes at 82% JPEG quality by default. If you uploaded an already-compressed JPEG, it has now been compressed twice. Raise it with the jpeg_quality filter, or upload PNG for graphics and screenshots where re-compression is visible: the format decision matters more than most people assume.

Uploads fail entirely on large files. Different problem, same root cause as the memory issue above: the resize happens during upload, and if PHP runs out of memory mid-resize, the upload fails after the file has already transferred. The file size limit shown in the uploader is about transfer, not about processing: a file can be well under the limit and still fail.

An image displays at the right size but the file is huge. The browser chose a large candidate from srcset because the sizes attribute told it the image would be displayed wider than it actually is. This is the single most common responsive-images mistake and it is worth understanding properly.

Choosing dimensions that hold up

A few rules that survive contact with real projects.

Upload larger than you need, but not enormous. Something between 2000 and 2560 pixels on the long edge gives WordPress room to derive every size, including the retina ones, without leaving a 5 MB original on disk forever.

Match your sizes to your breakpoints, not to round numbers. If your grid switches to two columns at 768 and your cards are then 360 pixels wide, a 640-pixel card size covers both the normal and the retina case. A 1200-pixel card size is waste in every scenario.

Decide the crop before the upload. Every automated crop is a guess about what matters in your picture. The guess is centre.

Choose the format with intent. Sizes are only half the weight question; the encoding is the other half.

Where this leaves you

The mechanism is not complicated once it is visible. One upload becomes eight or more files. Sizes appear only when the original was big enough. Themes and plugins add their own, silently, and only for images uploaded after they were activated. A visitor sees at most two of the files that exist.

What makes it feel complicated is that all of it happens with no interface. There is no screen in WordPress that shows you which sizes are registered, which ones exist for a given image, or how much disk they occupy: the information is in the database, and you have to go and get it.

That gap is the reason WunderPaint has a Media Library Manager: registered sizes, actual files per attachment, duplicates and orphans, listed rather than inferred. It also means you can crop deliberately before an upload rather than letting the centre crop decide, and set alt text while you are in there.

The plugin is free and stays free. But the more useful takeaway is the query itself: run wp_get_registered_image_subsizes() on your own site and see how many sizes you are creating on every single upload. On most sites the number surprises people.

WordPress Image Sizes Explained: Every File Created From a Single Upload

Table of Contents

Learn it by building something

Every week one thing you can make the same afternoon, from dynamic templates to 3D type. Written down step by step.

One mail a week, and then it ends.
Unsubscribe in one click.

Security & Privacy

What Your Photo Is Telling Everyone: An EXIF Viewer & Remover

Every photograph carries a block of tags nobody looks at: camera, lens, exposure, three timestamps, and often the coordinates of the room it was taken in. Read yours in the browser, then learn what each field means, who wrote it, and what quietly removes it.

Troubleshooting

WordPress Images Not Showing: Five Layers, Five Fixes

A broken image icon is not one problem. It is the same symptom produced by five different failures at five points in the request, and the fix for one does nothing for the other four. Read the server response first, then work down the layers with read-only commands.

SEO & Structured Data

Redirect Rule Generator: The Rules That Never Fire

A redirect list rarely breaks. It accumulates: a broad prefix rule that kills every rule below it, a target missing a trailing slash that doubles your hop count, a 301 where a 308 was needed. Generate the Apache, nginx and CSV versions of your rules, then walk a URL through them and watch where it actually goes.

WordPress Development

One Design, Two Hundred Names: Designing From a Spreadsheet

Somebody needs two hundred name badges by Thursday. The spreadsheet with all those names already exists, and typing them a second time is pure waste.

Security & Privacy

WordPress Salts and Passwords: The Eight Lines Nobody Rotates

The eight define() lines in wp-config.php sign every admin cookie and every nonce your site issues. What each one does, why Math.random cannot be trusted to make them, what actually breaks when you rotate them, and an offline generator for the replacements.

CSS & Front-End

CSS Gradient Generator: Gradients That Do Not Band

A gradient that looked smooth in the design tool grows stripes on the page. The cause is arithmetic: 8 bit colour, two similar colours and 1600 pixels to cover. How to count the steps before you ship, the three real fixes, and a builder that measures the banding for you.

Download the free WunderPaint Plugin for WordPress

The WunderPaint workspace with the layers panel, adjustment sliders, text style presets and the asset library along the bottom

The Image Editor & Design Studio

Everything described here can be done in the browser, on your own site. The live demo runs the full editor with nothing to install.

Free

Chaos Art

Autonomous painters make one-of-a-kind abstract art in 3D space - gestures, art movements, painterly media, and embeds that paint a new original for every visitor.

Pro

Particle Strokes

Paint with swarms of light: twenty-two movements, a stamp you draw yourself, and curves that give a stroke a shape - the swarm keeps painting for a few seconds after you let go.

Pro

City Diorama

Any place on earth as a miniature you could hold: real streets, water and building footprints raised into a 3D diorama - or wrapped around a sphere as your own tiny planet.

Free

Papercut Art

Layered paper pictures with real depth - a photo sliced along its actual depth into up to twenty layers, parametric landscapes, animals and clouds you can shape, letters with real counters, and a look that runs on three dials.

Pro

3D Earth Studio

A hyperrealistic globe - day and night with city lights, live clouds, atmosphere halo, country borders and highlights, click-to-place markers with flight-route arcs, satellite orbits, seamless rotation video and a live website embed.

Free

Mystic Studio

Turn a birth date into wall art - a real natal chart with houses and aspects, the moon of that night, zodiac and Chinese zodiac posters, numerology cards and a synastry wheel for two, in eight artful themes.

Free

Marble Bath

Marble paper on a virtual water bath - drop, rake and comb real Ebru patterns with gestures, flowers and classic recipes, razor-sharp at any size and re-editable as a layer.

Free

Day Ring

Turn a day into a beautiful circular schedule - colour-coded time blocks as arcs around a 24-hour clock, with concentric rings for overlaps, emoji, templates and a legend.

Free

Code Shot

Turn code into a gorgeous, share-ready image - syntax highlighting, editor themes, window frames and diff highlighting - then drop it into your design as a re-editable layer.

Pro

3D Solar System Studio

Build a date-accurate 3D solar system - real planet positions for any date, photoreal textures and one slider from artistic to true scale - then drop it into your design as an editable layer.