Short answer: WordPress speed is a stack, not a single setting. The order that produces results is: fix hosting first (TTFB and infrastructure), enable caching second (page + browser + object), optimize images third (format, size, lazy-loading), clean the database fourth, defer and minify CSS and JavaScript fifth, add a CDN sixth if your audience is geographically spread. Most slow sites are slow for the same handful of reasons, and most of those reasons can be fixed in an afternoon if you go in the right order.
| Optimization layer | Typical speed gain | Effort | Cost |
|---|---|---|---|
| Better hosting (NVMe, modern PHP, isolated resources) | -300 to -800ms TTFB | Half day migration | Hosting plan |
| Server-level page caching | 90-95% faster on cached pages | 5 min plugin install | Free with most managed hosts |
| Object caching (Memcached/Redis) | -100 to -400ms on uncached pages | 5-30 min setup | Free if host supports it |
| Image optimization (WebP + lazy load) | -1 to -4s on image-heavy pages | 1-3 hours initial sweep | Free or $5-15/month plugin |
| Database cleanup | -50 to -200ms on every uncached page | 30 min one-time | Free |
| CSS/JS deferral and minification | -200 to -1000ms LCP | 1-2 hours configuration | Free |
| Critical CSS inlining | -100 to -500ms LCP | Plugin handles it | Included in WP Rocket / LiteSpeed |
| CDN for global audience | -100 to -800ms outside origin region | 1-2 hours DNS setup | Free tier or $5-20/month |
| HTTP/3 / QUIC | -50 to -200ms on mobile | Server-side – check with host | Free if host supports |
What this guide covers: the entire WordPress optimization stack in priority order, when each layer matters and when it does not, what to install vs what to configure at the server level, the most common mistakes, and how to actually measure whether your changes worked.
A slow WordPress site costs you visitors, rankings, and revenue. Google uses page speed as a ranking factor through Core Web Vitals. Visitors who wait more than three seconds for a page to load are far more likely to leave than to engage. And every second of delay reduces conversions – whether that means fewer signups, fewer purchases, or fewer pages read. Speed is one ranking factor among many – for the full beginner setup, see WordPress SEO: a beginner’s guide to ranking your site.
The good news is that WordPress performance problems are predictable and fixable. Most slow sites share the same handful of causes: inadequate hosting, no caching, unoptimized images, bloated databases, too many plugins, and render-blocking CSS and JavaScript. Fix these in the right order and the improvement is dramatic.
This guide covers the optimization stack in priority order – from the changes that make the biggest difference to the ones that provide incremental gains on top of a solid foundation. If you are not sure which of those causes is actually your site’s problem – the site is slow, but you have not measured which layer is slow – start with why is my WordPress site so slow? A diagnostic guide to find the specific bottleneck before working through this fix list.
How to measure your site's speed#
Before optimizing anything, measure what you are working with. Two tools give you the data you need:
Google PageSpeed Insights (pagespeed.web.dev) tests your site against Google’s Core Web Vitals and provides both lab data and real-user data (if your site has enough traffic). It scores your site on a 0-100 scale and flags specific issues to fix. The real-user data (CrUX, the Chrome User Experience Report) is what Google actually uses for ranking signals, so optimize against that, not the synthetic lab score.
GTmetrix (gtmetrix.com) provides a waterfall chart showing every resource your page loads, how long each takes, and what blocks rendering. The waterfall is where you diagnose specific bottlenecks – a slow database response, a massive image, a render-blocking script. If a single resource takes 4 seconds to load while everything else takes 200ms, that is your problem.
Other useful tools:
- WebPageTest (webpagetest.org) – free, more configurable than GTmetrix; lets you test from specific geographic locations and connection speeds
- Chrome DevTools Lighthouse (built into Chrome’s developer tools) – same engine as PageSpeed Insights but runs locally
- Query Monitor (WordPress plugin) – shows database queries, hooks, and PHP errors per page load; the only way to spot a plugin causing slow queries
Test from a clean browser profile (or incognito) so cached extensions and login state do not skew results. Test the same page three times and use the median – the first run is often skewed by cold caches.
Core Web Vitals#
Google’s Core Web Vitals are the three metrics that matter most for both user experience and SEO rankings:
- Largest Contentful Paint (LCP) – how long until the largest visible element (usually the hero image or main heading) is rendered. Target: under 2.5 seconds.
- Interaction to Next Paint (INP) – how quickly the page responds when a user clicks, taps, or types. This replaced First Input Delay (FID) in March 2024. Target: under 200 milliseconds.
- Cumulative Layout Shift (CLS) – how much the page layout shifts unexpectedly as it loads (elements jumping around, images loading without reserved space). Target: under 0.1.
These are not abstract metrics. LCP directly correlates with perceived speed. INP determines whether the site feels responsive. CLS determines whether users accidentally click the wrong thing because a button moved. All three feed into Google’s ranking algorithm.
| Metric | Good | Needs improvement | Poor | Most common cause |
|---|---|---|---|---|
| LCP | < 2.5s | 2.5-4s | > 4s | Slow hosting, large hero image, render-blocking CSS |
| INP | < 200ms | 200-500ms | > 500ms | Heavy JavaScript on click handlers, third-party scripts |
| CLS | < 0.1 | 0.1-0.25 | > 0.25 | Images without dimensions, late-loading fonts, ads inserted after render |
If your site is failing one or more Core Web Vitals, the rest of this guide tells you which layer to fix to address each.
1. Hosting - the foundation#
No amount of optimization compensates for underpowered hosting. A WordPress site running on a shared server with a spinning hard drive, 512MB of RAM, and PHP 7.4 has a speed ceiling that no plugin can break through.
What matters in a hosting environment#
Storage type. NVMe SSDs are 5-10x faster than SATA SSDs for random read/write operations, which is exactly what database queries produce. A MySQL query that takes 50ms on a SATA drive might take 10ms on NVMe. Multiply that by 30-50 queries per page load and the difference is measurable. See why NVMe storage affects your site speed for the technical details.
PHP version. PHP 8.x is significantly faster than PHP 7.x for WordPress workloads. PHP 8.0 introduced the JIT compiler. PHP 8.1 and 8.2 added further performance improvements. Running an end-of-life PHP version is both a security risk and a performance penalty. Most hosts let you switch PHP versions in the control panel – if yours does not, that is a sign the host has not modernized and is part of the problem. To check what version you are on, see how to check your PHP version.
PHP-FPM workers. Every concurrent visitor that hits an uncached page needs a PHP-FPM worker to process the request. If all workers are busy, new requests queue up and response times spike. Hosting plans with too few workers handle traffic spikes poorly even if the individual responses are fast. For sites expecting sustained high-traffic loads, see WordPress high availability and high traffic hosting for what the stack actually needs.
Object cache availability. Having Memcached or Redis available for WordPress’s persistent object cache eliminates redundant database queries. This is infrastructure that needs to be provided by the host – it is not something a plugin can create on its own.
Resource isolation. On shared hosting where multiple accounts share the same CPU and memory, another account’s traffic spike can slow your site down. Container-based isolation prevents this by allocating dedicated resources per account. On Hostney, every account runs in its own container with guaranteed CPU, RAM, and PHP-FPM workers that are not shared with other accounts.
Web server. Nginx handles concurrent connections more efficiently than Apache for typical WordPress workloads. Most managed hosts run nginx (or a hybrid setup with nginx in front of Apache). If your host runs Apache only, you can still get a fast site – but the upper bound is lower.
When hosting is the bottleneck#
If your Time to First Byte (TTFB) is consistently above 600ms on uncached pages, hosting is likely the bottleneck. TTFB measures how long the server takes to start sending a response. A well-configured WordPress site on decent hardware should have uncached TTFB under 400ms. If yours is over a second, no amount of frontend optimization will make the site feel fast.
Test TTFB by opening your browser’s developer tools, going to the Network tab, reloading the page, and clicking on the document request. The “Waiting for server response” or “TTFB” line is the number you want.
If you suspect hosting is the issue but cannot tell whether it is the hosting or your own code, run a clean diagnostic before assuming you need to migrate. Sometimes the host is fine and a single rogue plugin is making the database slow.
When migrating hosts makes sense#
Migration is the right answer when:
- Your TTFB is over 800ms even after caching is enabled
- Your host charges extra for what is now table-stakes (object cache, modern PHP, NVMe storage, free SSL)
- Traffic spikes regularly cause 503 errors or extended slowdowns
- Your site grew past what the current plan was sized for and the next tier is expensive without proportional benefit
For the migration itself, see how to migrate WordPress to another hosting provider. For the broader migration picture (server-to-server, OS migration, cloud migration), see what is server migration.
2. Caching - the biggest single improvement#
Caching is the most impactful optimization for most WordPress sites. A properly cached page that takes 15 milliseconds to serve replaces a dynamically generated page that takes 300-800 milliseconds. For visitors, the difference is between a site that feels instant and one that feels sluggish. For your server, the difference is between handling a small traffic spike comfortably and exhausting PHP workers within seconds.
WordPress has multiple cache layers. Each layer addresses a different problem.
| Cache layer | What it stores | Lives where | Biggest impact |
|---|---|---|---|
| Browser cache | Static assets (CSS, JS, images, fonts) | Visitor’s browser | Returning visitor speed |
| CDN cache | Static and (sometimes) cached HTML | Geographically distributed edge servers | Global audience |
| Server page cache (FastCGI/Varnish) | Rendered HTML | Web server (nginx/Apache) | Skipping PHP entirely |
| WordPress page cache (plugin) | Rendered HTML | Disk inside
wp-content/
| When server-level cache is unavailable |
| Object cache (Memcached/Redis) | Database query results | RAM on the server | Logged-in pages, admin, WooCommerce |
| OPcache | Compiled PHP bytecode | RAM in PHP-FPM | Lower CPU per PHP request |
For a complete walkthrough of every cache layer and how to clear each, see how to clear the WordPress cache: every layer explained. For an honest comparison of caching plugins, see best WordPress caching plugins (honest comparison).
Page caching (server-level)#
Server-level page caching stores the complete HTML output of a page and serves it directly from Nginx or Apache without invoking PHP at all. The request never reaches WordPress – the web server reads the cached file and returns it. This is fundamentally faster than any PHP-based caching plugin because PHP is never loaded.
On Hostney, Nginx FastCGI caching is built into the stack. The Hostney Cache plugin connects WordPress to the server-level cache automatically – when you publish or update a post, the relevant cached pages are purged so visitors always see fresh content. There is nothing to configure beyond installing the plugin. The plugin also handles Gutenberg’s duplicate save requests, archive page purging, and bulk operation fallbacks without any manual setup.
On other hosts, you typically need a caching plugin like WP Rocket, W3 Total Cache, or LiteSpeed Cache to generate cached pages. These plugins work by creating static HTML files and serving them through PHP or
.htaccess
rewrite rules. This is faster than generating the page dynamically, but slower than server-level caching because PHP still loads on every request to determine whether a cached file exists.
What gets cached and what does not: Page caches store the HTML for non-logged-in visitors. They bypass logged-in users (because the admin bar and per-user content would leak between sessions), WooCommerce cart and checkout pages, and any page with query strings used as session identifiers. This is correct behavior – caching those pages would cause data leaks.
If you have implemented user-specific content on public pages (a “Welcome back, [name]” greeting on the homepage, for example), that page cannot be page-cached without breaking the personalization. Either remove the personalization, move it to JavaScript that runs after the page loads, or accept that the page will not benefit from caching.
Browser caching#
Browser caching tells visitors’ browsers to store static files (images, CSS, JavaScript, fonts) locally so they do not need to be downloaded again on subsequent page loads. This is configured through HTTP cache headers.
Most WordPress hosts set these headers by default. If yours does not, a caching plugin can add them, or you can add them in your
.htaccess
or Nginx configuration:
# Example Nginx configuration for browser caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2|svg)$ {
expires 365d;
add_header Cache-Control "public, immutable";
}
The
.ico
rule above also covers favicons, which is why favicon updates do not always show up immediately after you change the site icon – long cache headers mean returning visitors hold on to the old version until the cache expires or the file URL changes.
Browser caching does not help first-time visitors, but it makes a significant difference for returning visitors and for navigation within your site (clicking from one page to another reuses cached CSS, JS, and fonts). This is also why self-hosted fonts perform better than externally-loaded ones – how to add custom fonts to WordPress covers the full tradeoff including
font-display: swap
, preloading, and the DNS/TLS savings of serving fonts from your own domain.
Object caching (Memcached/Redis)#
WordPress runs dozens of database queries per page load, and many fetch the same data repeatedly: site options, active plugins, theme settings, rewrite rules, user roles. Without an object cache, WordPress re-fetches this data from MySQL on every request.
A persistent object cache stores these query results in memory (Memcached or Redis) and serves them in microseconds instead of querying the database. The impact is most significant on pages that cannot be fully cached – admin pages, WooCommerce cart and checkout, logged-in user dashboards – because those pages still benefit from faster underlying queries even though the full page is not cached.
On Hostney, Memcached is available on all plans. The Hostney Cache plugin installs the
object-cache.php
drop-in and connects to your account’s isolated Memcached instance automatically. On other hosts, you can use plugins like Redis Object Cache or W3 Total Cache’s object cache module, provided your host has Redis or Memcached available.
For a deeper understanding of how cache hits and misses affect your site’s performance and server capacity, see what is a cache miss and how does it affect performance.
OPcache#
OPcache is built into PHP itself. It stores the compiled bytecode of PHP scripts in shared memory so PHP does not have to re-parse and re-compile the same files on every request. WordPress core, plugin files, and theme files are all OPcache-eligible.
Most hosts have OPcache enabled by default with reasonable settings. If yours does not, OPcache is a free 20-50% improvement on every PHP request. You can verify it is enabled by running
php -i | grep opcache
over SSH or by checking phpinfo output through a temporary page.
The one OPcache gotcha: when you deploy code changes, OPcache may serve the old bytecode until it detects the file changed. Most hosts have
opcache.validate_timestamps=1
set, which checks file modification times and refreshes automatically. If your site is not picking up code changes after deploy, restart PHP-FPM or call
opcache_reset()
from a one-off script.
Cache invalidation: the hard part#
Cache invalidation is famously hard. The right cache layer cleared at the wrong time produces stale content. The wrong layer cleared at the right time produces no benefit.
The pattern that works: trust the plugin or platform to handle automatic invalidation for routine events (publish, update, comment, taxonomy change), and clear caches manually after non-routine events (theme changes, widget changes, migrating between hosts, bulk database operations, manual database edits, importing content).
The Hostney Cache plugin queues invalidations and runs them at WordPress shutdown so saving a post does not block on the cache purge. If more than 15 URLs need invalidating, it falls back to a full cache clear (sensible for bulk operations).
3. Image optimization#
Images are typically the largest files on any WordPress page. An unoptimized hero image can be 2-5MB. A product page with ten unoptimized photos can load 20-30MB of images. This is the single biggest cause of slow LCP scores. The Image and Gallery blocks themselves are covered in how to add images to WordPress; the rules below assume you already know how to insert an image and are looking to make the ones already on the site faster.
Serve images in modern formats#
WebP is 25-35% smaller than JPEG at equivalent visual quality. AVIF is even smaller (around 50% smaller than JPEG) but has slightly less browser support. Convert your images to WebP (or AVIF with a JPEG fallback) before uploading, or use a plugin that converts them automatically.
Plugins that handle conversion: ShortPixel, Imagify, Smush Pro, EWWW Image Optimizer, Optimole. These compress and convert images either on upload or in bulk for existing media. For the head-to-head comparison and which fits which kind of site, see best WordPress image optimization plugins (free and paid).
A few hosts handle WebP/AVIF conversion at the server level – you upload JPEGs and the server serves WebP/AVIF transparently to browsers that support them. This is faster than plugin-based conversion because no plugin runs on each image upload, but the feature is uncommon enough that you should not assume your host has it. Most managed WordPress hosting (including Hostney) leaves image format conversion to the plugin layer.
Video is the other heavy-media culprit, and the rules are different – self-hosted video files can dwarf everything else on a page combined. For how to handle video without wrecking page speed, see how to add and embed videos in WordPress. Animated GIFs are a third category that surprises people – a single 30-second GIF often weighs as much as the rest of the page combined, and converting it to MP4 or WebM cuts the size by 90% with no visible quality loss; how to add animated GIFs to WordPress covers the conversion and the Video block setup that plays inline like a GIF would.
Correctly size images#
WordPress generates multiple sizes of each image you upload (thumbnail, medium, large, full). Your theme should use the appropriately sized version for each context. A 300px-wide thumbnail area should not load the 2000px-wide original.
Check your pages with GTmetrix – it flags images that are served at a larger size than they are displayed. If your theme’s content area is 720px wide, there is no reason to serve a 1920px-wide image.
For responsive images, modern WordPress automatically generates
srcset
attributes that serve different sizes to different screen widths. This is on by default on every theme that uses
the_post_thumbnail()
or core image blocks. If your theme bypasses
wp_get_attachment_image_srcset()
and outputs raw
<img>
tags, you lose this benefit – check the page source for
srcset
attributes on images, and if they are missing, that is a theme bug worth fixing.
While you are reviewing images, this is also a good time to check that each one has proper alt text. It does not affect page speed directly, but it is part of image SEO and accessibility, and doing both passes at once is faster than coming back later – see how to add alt text to images in WordPress.
Lazy loading#
Lazy loading defers the loading of images that are not visible in the viewport until the user scrolls to them. This dramatically reduces initial page load time because the browser only downloads images the visitor can actually see.
WordPress has native lazy loading built in since version 5.5. It automatically adds
loading="lazy"
to images and iframes in post content. Most modern themes support this without any additional configuration. For heavy third-party iframes that core does not auto-detect (custom-pasted iframes from Google Forms or other SaaS embeds), add
loading="lazy"
manually in the iframe attributes – the deferred load saves several hundred KB of third-party JavaScript on initial paint.
For the LCP image (typically the hero image or first visible image), lazy loading should be disabled. Lazy loading the LCP image delays it, which directly hurts your LCP score. Well-coded themes exclude above-the-fold images from lazy loading. If yours does not, you can add
fetchpriority="high"
to the LCP image element to tell the browser to prioritize it.
Image dimensions and CLS#
Every image should have explicit
width
and
height
attributes set in HTML. Without dimensions, the browser does not know how much space to reserve for the image until it loads, which causes the page layout to shift when the image arrives – a Cumulative Layout Shift (CLS) penalty.
Modern WordPress core sets these attributes automatically for images inserted through the block editor. The risk is custom themes, page builders that strip attributes during their rendering, or images inserted through
<img>
tags in custom HTML.
Check your CLS score in PageSpeed Insights. If it is above 0.1, the most common cause is images without dimensions. Other causes are late-loading fonts (which cause text reflow), and ads or embeds that insert content after the surrounding layout has already rendered.
4. Database optimization#
WordPress databases accumulate bloat over time: post revisions, auto-drafts, trashed posts, expired transients, spam comments, and orphaned metadata. This bloat slows down queries because MySQL has to scan through more data.
What to clean up#
- Post revisions – WordPress saves every revision of every post by default, with no limit. A post edited 50 times has 50 revisions in the database, each a full copy of the post content. Limit revisions by adding to
wp-config.php:
define('WP_POST_REVISIONS', 5);
WordPress revisions: how to use and control them covers how revisions work, how to clean up existing ones, and how to pick the right limit.
- Auto-drafts and trashed posts – WordPress creates auto-drafts as you type and keeps trashed posts for 30 days. Clean up old ones periodically.
- Expired transients – transients are temporary cached values. WordPress is supposed to clean up expired ones, but some linger. Plugins that set transients with no expiry are especially problematic.
- Orphaned post meta and term relationships – when posts are deleted, their metadata sometimes stays behind.
- Spam and trashed comments – these accumulate if not purged regularly.
For a complete walkthrough, see WordPress database optimization: how to clean up and speed up your database.
wp_options table bloat#
The
wp_options
table is queried on every page load and is the most common source of database-related slowness. Plugins that store large amounts of serialized data in
wp_options
with
autoload=yes
force WordPress to load that data into memory on every request.
Check what is autoloaded:
SELECT option_name, LENGTH(option_value) AS size
FROM wp_options
WHERE autoload = 'yes'
ORDER BY size DESC
LIMIT 20;
If you see entries that are hundreds of kilobytes or larger, those are candidates for investigation. Common culprits include analytics plugins caching report data, form plugins storing submission logs, and caching plugins storing configuration as serialized arrays.
To run this query, you need access to phpMyAdmin or the MySQL command line – WordPress does not expose direct SQL access from the admin interface. Most hosting control panels include phpMyAdmin.
Database engine: MyISAM vs InnoDB#
Older WordPress installations may have tables on the MyISAM storage engine, which has worse concurrent-write performance than InnoDB. Modern WordPress installations default to InnoDB, but tables migrated from older sites may still use MyISAM.
Check by running
SHOW TABLE STATUS;
in phpMyAdmin. If any tables show
Engine: MyISAM
, convert them to InnoDB:
ALTER TABLE wp_posts ENGINE=InnoDB;
The conversion is safe but takes a few seconds per table. Run it during low-traffic periods.
MariaDB vs MySQL#
If your host runs MariaDB instead of MySQL, performance is typically equivalent or slightly better – MariaDB is a drop-in MySQL replacement with some optimizations. See MySQL vs MariaDB: which should you use for the technical comparison. WordPress works identically on both.
What you cannot control: if your host is running an old MySQL or MariaDB version on shared infrastructure, your site is slower than it would be on modern versions, but the host’s other tenants are also affected and you cannot upgrade unilaterally.
5. CSS and JavaScript optimization#
Unoptimized CSS and JavaScript files can block page rendering and add significant weight to page loads.
Defer non-critical JavaScript#
By default, JavaScript files in the
<head>
block rendering – the browser stops parsing HTML to download and execute each script. Deferring non-critical scripts allows the HTML to render while scripts load in the background:
<script src="script.js" defer></script>
The
defer
attribute tells the browser to download the script in parallel with HTML parsing and execute it after the document is fully parsed. The
async
attribute is similar but executes the script as soon as it downloads, regardless of parsing state – useful for independent scripts like analytics.
In WordPress, this is typically handled by plugins. Autoptimize, Asset CleanUp, Perfmatters, and WP Rocket all offer options to defer or delay JavaScript loading. If you are building a custom theme, you can set defer directly when enqueuing scripts.
Minify CSS and JavaScript#
Minification removes whitespace, comments, and unnecessary characters from CSS and JavaScript files without changing functionality. A 100KB CSS file might become 70KB after minification. The savings are modest per file but add up across all assets.
Plugins: Autoptimize, WP Rocket, LiteSpeed Cache, and Asset CleanUp all handle minification.
Common minification gotcha: aggressive minification can break sites that rely on specific class names or that have JavaScript depending on whitespace. Always test minification on a staging site before enabling on production. If your site breaks after enabling minification, exclude the offending file from minification rather than disabling it entirely – most plugins let you list specific files to skip.
Eliminate render-blocking resources#
A CSS file in the
<head>
blocks rendering until it is fully downloaded and parsed. For a large CSS file loaded from a slow CDN, this can add hundreds of milliseconds to LCP.
The fix is to inline critical CSS (the minimum CSS needed to render above-the-fold content) and defer the rest. This is complex to do manually but plugins like WP Rocket and Perfmatters automate it. Critical CSS generation analyzes each page type and extracts only the CSS rules needed for the initial viewport.
The tradeoff: critical CSS adds 5-15KB to your HTML and saves 50-300ms on LCP. For most sites this is a net win. For sites with very small CSS files (under 30KB), critical CSS may not be worth the added complexity.
Reduce plugin overhead#
Each WordPress plugin adds its own CSS and JavaScript files, and many load these files on every page whether needed or not. A contact form plugin loading its CSS and JS on every page even though the form only appears on the Contact page wastes bandwidth and rendering time. Popup plugins are the worst offender in this category – see best WordPress popup plugins for which ones lazy-load and which load sitewide.
Asset CleanUp and Perfmatters let you disable specific plugin assets on pages where they are not needed. This is one of the most effective optimizations for sites with many plugins because it directly reduces the number of HTTP requests and the total file size per page.
The audit process: open your homepage in Chrome DevTools, go to the Network tab, filter by JS or CSS, and look at every file. For each file that comes from a plugin, ask: does the homepage need this? If a contact form plugin’s JS is loading on the homepage and there is no form on the homepage, that is bandwidth wasted. Asset CleanUp lets you disable that asset specifically for the homepage URL.
Reduce third-party scripts#
Third-party scripts (Google Analytics, Facebook Pixel, chat widgets, marketing tags) often load synchronously and block rendering. Each one adds its own DNS lookup, TLS handshake, download, and execution time.
The honest framing: marketing teams want all these scripts. Performance teams do not. The compromise is usually to load them asynchronously, defer non-essential ones, and consolidate where possible (Google Tag Manager replaces 5-10 individual scripts with one container).
Check the Network tab waterfall for any third-party domain that is taking >500ms. That is your candidate for deferral or removal.
6. CDN for static assets#
A Content Delivery Network caches your static files (images, CSS, JavaScript, fonts) on servers distributed around the world. When a visitor in Tokyo loads your site hosted in London, the static files are served from a nearby CDN edge server instead of crossing the Atlantic.
CDNs help most when your audience is geographically distributed and your static assets are large (image-heavy sites, sites with many CSS/JS files). For a small site with a local audience, the improvement may be minimal – small-business and locally-scoped sites usually get more value from the other levers covered in WordPress SEO tips for small businesses.
The practical decision comes down to your traffic pattern, asset size, and budget. For a detailed breakdown of when a CDN is worth it and when it is not, see should I use a CDN for my website.
Setting up a CDN with WordPress#
Most CDN providers (Cloudflare, Bunny CDN, KeyCDN, StackPath) offer WordPress plugins or straightforward DNS configuration. The typical setup involves:
- Sign up with a CDN provider.
- Configure your domain (either a full DNS proxy like Cloudflare, or a CDN subdomain like
cdn.example.com). - Install the provider’s WordPress plugin or use a plugin like CDN Enabler to rewrite asset URLs.
Cloudflare’s free tier is a common starting point. It provides a global CDN, DDoS protection, and basic optimizations at no cost.
CDN-cached HTML (full-page CDN caching)#
Some CDNs (Cloudflare with Page Rules or Cache Rules, Bunny CDN with Edge Rules) can also cache full HTML pages, not just static assets. This pushes your origin server work down dramatically because the CDN serves cached HTML directly without ever touching your hosting.
The tradeoff is invalidation. CDN-cached HTML needs to be purged when content changes, just like origin-server cached HTML. If your caching plugin does not push purges to the CDN, you will see stale content. WP Rocket, LiteSpeed Cache, and W3 Total Cache all support Cloudflare cache integration. The Hostney Cache plugin handles origin cache automatically; for CDN-level caching on top, you configure the CDN’s cache rules separately.
Full-page CDN caching is most useful for sites with traffic well above what a single origin server can handle. For most WordPress sites, origin-level page caching is enough.
7. HTTP/2 and HTTP/3#
HTTP/2 allows the browser to download multiple files simultaneously over a single connection instead of opening a new connection for each file. This eliminates the latency overhead that HTTP/1.1 had with multiple assets – the browser no longer queues requests sequentially.
HTTP/3 takes this further with QUIC, a protocol built on UDP that eliminates head-of-line blocking and reduces connection setup time. For mobile users on unreliable networks, HTTP/3 makes a noticeable difference.
Both protocols are server-side configurations, not something you install as a plugin. Most modern hosts support HTTP/2. HTTP/3 support is less common but growing. You can check whether your site supports either by looking at the protocol column in your browser’s developer tools Network tab, or by visiting
https://http3check.net/
for an external test.
On Hostney, HTTP/3 (QUIC) is enabled across all web servers. The
Alt-Svc: h3=":443"; ma=86400
response header advertises HTTP/3 support, and modern browsers upgrade the connection automatically on subsequent requests.
The real-world impact of HTTP/3 is most visible on mobile networks with high latency or packet loss. On a wired desktop connection, the difference between HTTP/2 and HTTP/3 is usually under 50ms. On a 4G mobile connection in a rural area, it can be 200-500ms.
8. WooCommerce-specific optimization#
WooCommerce stores have additional complexity because cart, checkout, and account pages cannot be page-cached – they contain per-user data. The optimization surface is different from a brochure site.
Key WooCommerce-specific considerations:
- Cart fragments AJAX: WooCommerce’s
wc-ajax=get_refreshed_fragmentsrequest runs on every page load by default to keep the mini-cart updated. This adds 100-400ms to every page on stores using a mini-cart. Some optimization plugins disable it for non-cart pages. - Object cache is critical: product data, category queries, and cart calculations all benefit dramatically from Memcached or Redis.
- Database queries grow with order volume: stores with 10,000+ orders need to clean up customer sessions, abandoned carts, and order metadata aggressively.
- Payment gateway scripts: Stripe, PayPal, and other payment scripts add weight to checkout pages. They are necessary on the checkout page, not on the homepage.
For the full WooCommerce optimization checklist, see WooCommerce speed optimization: how to make your store faster.
9. Mobile performance#
Mobile traffic accounts for the majority of WordPress traffic for most sites. Google uses mobile-first indexing, meaning the mobile version of your site is what determines search rankings.
Mobile-specific considerations:
- Network conditions: mobile networks have higher latency and lower throughput than desktop. A site that loads in 2 seconds on a wired desktop might take 6-8 seconds on a 4G connection.
- CPU: mobile CPUs are slower than desktop CPUs. JavaScript that runs in 50ms on desktop might take 200-400ms on mobile.
- Smaller screens, smaller images needed: serving 1920px images to a 375px-wide mobile screen wastes bandwidth. Responsive images via
srcsetmatter more on mobile. - Touch responsiveness: INP (Interaction to Next Paint) is heavily influenced by JavaScript on click and tap handlers. Heavy JavaScript causes laggy mobile interactions even when load time is fine.
Test mobile performance with PageSpeed Insights’ Mobile tab and with Chrome DevTools’ device emulation (set to “Slow 4G” throttling). Real-world mobile performance is often very different from desktop performance on the same site.
10. Common Core Web Vitals fixes#
Each Core Web Vital fails for predictable reasons. The fixes are direct.
LCP > 2.5s#
The Largest Contentful Paint is usually the hero image or main heading. Most LCP problems trace to one of:
- Slow TTFB. Hosting bottleneck. See section 1.
- Hero image too large or unoptimized. Compress, convert to WebP, ensure correct size. See section 3.
- Hero image lazy-loaded. Remove
loading="lazy"from above-the-fold images. - Render-blocking CSS or JS. Defer non-critical resources or inline critical CSS. See section 5.
- Web fonts loading after the LCP element. Preload the font file or use
font-display: swap. See how to add custom fonts to WordPress.
INP > 200ms#
Interaction to Next Paint fails when JavaScript blocks the main thread when a user interacts. Fixes:
- Heavy click handlers. Reduce JavaScript that runs on click. Defer non-essential scripts.
- Third-party tag managers. Tag managers can fire dozens of scripts on user interaction. Consolidate or remove unused tags.
- Long-running animations. CSS animations on the GPU are cheap; JavaScript animations on the main thread are expensive. Use CSS where possible.
- Excessive layout thrashing. When JavaScript reads layout properties (e.g.,
offsetHeight) and then writes (e.g.,style.height) repeatedly, the browser has to recalculate layout each time. Batch reads and writes.
CLS > 0.1#
Cumulative Layout Shift fails when elements move around as the page loads. Fixes:
- Images without dimensions. Always set
widthandheightattributes. Modern WordPress core does this automatically; the risk is custom themes. - Web fonts. When a custom font loads, text reflows from the fallback font to the custom font. Use
font-display: swapand reserve space withsize-adjustorfont-display: optionalif appropriate. - Late-loading ads or embeds. Reserve space for ads with CSS before they load. Otherwise the layout shifts when the ad arrives.
- Cookie consent banners. A banner that appears 500ms after page load and pushes content down is a major CLS hit. Pre-position the banner with absolute or fixed CSS.
How long does each optimization take to implement#
Estimates are for a typical WordPress site without unusual complexity.
| Task | Time | Skills required |
|---|---|---|
| Switch PHP version in hosting control panel | 5 minutes | None |
| Install + configure caching plugin | 15-30 minutes | Basic |
| Enable object cache (if host has Redis/Memcached) | 5-15 minutes | Basic |
| Bulk image optimization (existing media library) | 1-3 hours wall time, mostly waiting | Basic |
| Database cleanup with WP-Optimize | 30-45 minutes | Basic |
| Configure JavaScript deferral and minification | 30-60 minutes including testing | Intermediate |
| Critical CSS generation (plugin handles it) | 15-30 minutes | Basic |
| Set up CDN with Cloudflare free | 30-90 minutes | Intermediate (DNS) |
| Disable unnecessary plugin assets per page | 1-3 hours for thorough audit | Intermediate |
| Migrate to a faster host | 2-6 hours active work, 24-72h propagation | Intermediate |
| Custom critical CSS hand-tuned | 4-8 hours per page template | Advanced |
| Database engine conversion to InnoDB | 5-15 minutes | Advanced (SQL) |
If you are doing all of this in one session, budget a full day and accept that some tasks will reveal subtler issues that take longer.
Common WordPress speed mistakes#
The mistakes are predictable. Most slow WordPress sites are slow because of one or more of these.
Stacking caching plugins. Running WP Rocket and W3 Total Cache simultaneously – or any two caching plugins – creates conflicts. Each tries to control the cache directory, the
object-cache.php
drop-in, and HTTP headers. The result is unpredictable behavior, sometimes worse performance than no caching at all.
Optimizing without measuring. “I installed a caching plugin and the site feels faster” is not data. Test before, change one thing, test after. Without numbers you cannot tell what worked, what broke, and what was placebo.
Optimizing the homepage and ignoring everything else. Visitors enter on blog posts, product pages, and landing pages, not the homepage. Test each major page type. The homepage is often the slowest because it loads the most content; the inner pages are usually where customers spend time.
Trusting GTmetrix’s grade as the goal. A “Grade A” GTmetrix score does not mean the site is fast for real users. Grade A on GTmetrix can coexist with poor real-world Core Web Vitals because the synthetic test runs from a single location with optimal conditions. Use GTmetrix to find waterfall problems, but use PageSpeed Insights’ real-user data (CrUX) for the real-world signal.
Adding more plugins to fix performance. Each “performance” plugin adds its own assets. Stacking SG Optimizer + WP Rocket + Smush + Autoptimize + Asset CleanUp creates conflict and complexity. Choose one tool per job: one caching plugin, one image optimizer, one asset manager. If a plugin is not actively contributing, remove it.
Using lazy loading on the LCP image. This is a regression introduced by enabling lazy loading globally. The LCP image must load eagerly. Check that your hero image does not have
loading="lazy"
on it.
Ignoring third-party scripts. A site can be perfectly optimized internally and still be slow because Facebook Pixel, Hotjar, an old Disqus widget, and three different analytics tools are loading 800KB of JavaScript before anything else can render. Audit your third parties.
Running a database optimizer on every page load. Some plugins offer “database optimization” that runs on a schedule; others claim “real-time optimization.” A
OPTIMIZE TABLE
query is an expensive operation. Run database cleanup manually or weekly via WP-Cron, not on every page load.
Treating caching as a substitute for fixing slow code. Caching makes slow pages fast for cached requests. It does not make slow code faster – it just runs it less often. If your homepage is slow because of a plugin running an N+1 query, caching hides the symptom but the underlying problem comes back the moment cache is bypassed (logged-in users, admin pages, after every cache flush).
Migrating hosts to fix code problems. Sometimes the host is fine and one plugin is slow. Migrating moves the slow plugin to a new server where it is still slow. Diagnose first – why is my WordPress site so slow helps separate hosting bottlenecks from code bottlenecks before you commit to the migration cost.
How to measure improvement#
After every change, re-test:
- Three test runs in incognito, different times of day if possible. Use the median value, not the best.
- PageSpeed Insights’ real-user data section – this is what Google ranks against. The lab score above it is synthetic.
- GTmetrix waterfall – check whether the resources you targeted are now smaller, faster, or eliminated.
- Server response time on uncached pages – the cache should not change uncached TTFB; if it did, something is wrong.
- Visit your own site as an anonymous user – your subjective feel matters too, but only after the numbers confirm the change.
A change that improves PageSpeed Insights but breaks the site is not a win. After every optimization, click through the major user flows: homepage → category → post → contact form, or homepage → product → cart → checkout for WooCommerce. Make sure nothing visually broke and nothing functionally broke.
Quick checklist#
If you want a priority-ordered list to work through:
- Measure first. PageSpeed Insights, GTmetrix, Query Monitor for slow database queries. Identify what is actually slow before changing anything.
- Check TTFB. If it is over 600ms on uncached pages, investigate hosting first.
- Enable server-level page caching (or install a caching plugin if your host does not handle it).
- Enable object caching (Memcached or Redis) if your host supports it.
- Update to the latest PHP version your plugins and theme support.
- Compress and resize images. Convert to WebP. Bulk-optimize the existing media library.
- Verify above-the-fold images are not lazy-loaded. Add
fetchpriority="high"to the LCP image. - Clean up the database – revisions, transients, auto-drafts. Limit revisions in
wp-config.php. - Defer non-critical JavaScript and minify CSS/JS. Test thoroughly after enabling.
- Disable plugin assets on pages where they are not needed (Asset CleanUp, Perfmatters).
- Audit third-party scripts. Defer or remove anything that is not essential.
- Consider a CDN if your audience is geographically spread.
- Verify HTTP/2 or HTTP/3 is enabled at the server level.
- Measure again with PageSpeed Insights and GTmetrix. Compare before and after.
Start at the top. Each level builds on the one before it. Deferring JavaScript on a site with no caching and unoptimized images is polishing the wrong layer.
How Hostney handles WordPress speed#
The optimization stack above is generic – the same advice applies regardless of host. Where Hostney specifically lands within that stack:
Hosting layer: Every account runs in its own container with dedicated CPU and memory, NVMe storage, modern PHP versions (5.6 through 8.5 with per-account switching), and PHP-FPM workers that are not shared with other tenants. nginx is the web server, with HTTP/3 (QUIC) enabled by default.
Caching layer: nginx FastCGI page caching is built into the server configuration for every account. The Hostney Cache plugin connects WordPress events (publish, update, comment, taxonomy change) to the cache so purges are automatic. Per-account Memcached over a Unix socket handles object caching – the plugin manages the
object-cache.php
drop-in automatically. OPcache is enabled per PHP-FPM pool.
Image and asset layer: Hostney does not bundle plugin-style image optimization or critical-CSS generation – those are applications of the optimization plugins discussed above (ShortPixel, Imagify, WP Rocket, Autoptimize). Where Hostney does help is at the network layer: HTTP/3 (QUIC) reduces connection setup time, and built-in browser caching headers reduce repeat downloads.
The honest framing: server-level page caching and object caching cover the parts that benefit most sites the most. Beyond those, the optimization layer is genuinely site-specific – which images need optimization, which scripts can be deferred, what CDN strategy makes sense – and that work happens in WordPress with the plugins already discussed in this guide. The hosting layer sets the upper bound; the application layer fills the rest.
For the bot-detection and security layer that runs alongside caching (and which preserves crawl budget by filtering bot traffic before it consumes PHP workers), see how to stop bot traffic at the origin.
Frequently asked questions#
Can I make any WordPress site fast?#
Within reason, yes. The constraint is rarely WordPress itself – it is the combination of host, theme, and plugin choices. A WordPress site on a managed host with a well-coded theme and a focused plugin set can routinely score 90+ on PageSpeed Insights. A WordPress site on shared hosting with a bloated theme builder and 60 plugins cannot, regardless of how many caching plugins you install.
How fast should my site be?#
For Core Web Vitals: LCP under 2.5s, INP under 200ms, CLS under 0.1. For absolute speed: under 2 seconds full page load on desktop, under 4 seconds on mobile 4G. These are floors, not targets – faster is always better, but visitors stop noticing improvements past those thresholds.
Do caching plugins make WordPress secure?#
No. Caching is a performance feature, not a security feature. A cached page can still be a vulnerable page. For security, see is WordPress secure and how to harden it.
Will optimization break my site?#
Some changes can. Aggressive minification can break themes that depend on specific class names. Deferring JavaScript can break plugins that expect synchronous execution. Enabling lazy loading on the LCP image hurts speed. The fix is to test in a staging environment before applying changes to production, and to apply optimizations one at a time so you can identify what broke.
How much improvement is realistic?#
For a typical WordPress site that has not been optimized: switching to a fast host plus enabling caching plus optimizing images usually produces 3-5x improvement on TTFB and LCP. From a 6-second load time to a 1.5-2 second load time is a normal outcome. Going from 2 seconds to 1 second requires more careful work. Going from 1 second to 0.5 seconds is the realm of dedicated performance engineering.
Should I worry about the GTmetrix or PageSpeed Insights score?#
Worry about Core Web Vitals from real-user data, not the synthetic score. A 100 score on GTmetrix with poor field data on PageSpeed Insights’ real-user section means your synthetic test passes but your actual visitors are seeing a slow site. The reverse – a 70 score on GTmetrix with good real-user data – means your real visitors are happy and the synthetic test is being pessimistic.
Will WordPress get slower as my content grows?#
Sometimes, but mostly because the database grows. A site with 100 posts and a site with 100,000 posts have similar page-load times if both are correctly indexed and cached. Where growth hurts is in admin operations (loading post lists), in queries that scan unindexed columns, and in the wp_options table accumulating bloat. The database optimization article covers maintenance for growing sites.
What is the single fastest improvement I can make today?#
If you have not enabled caching: install a caching plugin or enable your host’s server-level cache. That single change usually produces 50-90% TTFB improvement on uncached pages becoming cached. Everything else builds on that foundation.
Further reading#
This guide covers the high-level optimization stack. Deeper articles for each layer:
- Diagnosing what is slow: why is my WordPress site so slow? A diagnostic guide
- Caching specifically: how to clear the WordPress cache: every layer explained, best WordPress caching plugins (honest comparison), what is a cache miss and how does it affect performance, how Hostney handles WordPress cache purging automatically
- Database: WordPress database optimization, WordPress revisions: how to use and control them
- Hosting: how to choose WordPress hosting, why NVMe storage affects your site speed, WordPress hosting requirements, WordPress high availability, managed vs unmanaged WordPress hosting
- WooCommerce: WooCommerce speed optimization
- Network: should I use a CDN, HTTP/3 (QUIC) explained
- Server stack: PHP-FPM explained, end-of-life PHP, how to check your PHP version, nginx vs Apache for WordPress
- Backups (so you can experiment safely): best WordPress backup plugins, how to back up WordPress manually
Speed is a process, not a destination. Sites grow, plugins change, and traffic patterns shift. Re-measure quarterly, fix what regressed, and keep the plugin count honest. Most WordPress sites are slow for the same handful of reasons – and once those reasons are addressed, staying fast is mostly maintenance, not heroics.