A slow WooCommerce store usually has a specific cause: the server, the database, a plugin, a background job or what the browser has to download. It’s less common for everything to be a little too slow. So the first step isn’t installing a caching plugin. It’s finding out where the time goes.
This guide walks through troubleshooting in a fixed order: which pages are slow, how to measure them, and what to look for in each layer. If you’d like to understand what happens between a click and a finished page in WordPress first, start there.
Where is it slow?
“The store is slow” covers very different problems. Before you measure anything, write down which pages are slow and for whom. That usually points straight at the layer to start with.
| What you notice | Where the cause usually is | Start here |
|---|---|---|
| Every page is slow, including the home page | The server, PHP or a missing page cache | Server, caching |
| The home page is fast, but cart and checkout are slow | Pages that can’t be cached: the database, plugins, payment or shipping extensions | Database, plugins, our guide to slow checkout |
| The admin is slow, especially the orders list | Order data in wp_postmeta, background jobs and admin-ajax | Database, background jobs, our guide to a slow admin |
| Category pages with filters, or search, are slow | Heavy database queries | Database |
| The page appears quickly but takes long to become usable | Images, scripts and third-party code in the browser | Frontend |
| It has gotten slower over time | Data that grows: orders, sessions, autoloaded options, scheduled actions | Database, background jobs |
Measure before you change anything
The key distinction is between the server’s response time and everything that happens afterward in the browser. The server’s response time is called TTFB (time to first byte): the time from the browser asking for the page until the first byte comes back. Google’s own guidance on web.dev calls a TTFB of 0.8 seconds or less good. If it’s high, compressing images won’t help, and our guide to high TTFB is the place to start. If it’s low but the page still feels slow, the problem is in the browser.
Measure the page that’s actually slow, and measure it without the cache. A product page served from the page cache tells you nothing about how fast checkout is. Here’s how to get a useful picture:
- Open your browser’s developer tools (F12), go to the Network tab and reload the page. Click the page’s own request and look at “Waiting for server response” under Timing. Do it a few times, and add a product to the cart first when you measure cart and checkout.
- Run the page through PageSpeed Insights. The top shows data from real visitors (if the page gets enough traffic), the bottom a single lab test. The first is what Google uses.
- Install Query Monitor, ideally on a copy of the store. For every page it shows how much time the database and PHP take, and which plugin is behind the slowest queries.
Write the numbers down. When you change something later, it’s the only way to know whether it helped.
The server and hosting
If TTFB is high on every page, even the simplest ones, start with the server. WooCommerce publishes its own server recommendations, and a store on an old PHP version or with too little memory for WordPress will be slow whatever else you do. Check the PHP version and memory limit under WooCommerce → Status.
Next is how many requests the server can handle at once. Every page that doesn’t come from a cache occupies a PHP process while it’s being built. Shared hosting and small plans have few of them, and when they’re busy, the next visitors wait in line. You notice it first at busy times and in checkout, because those are exactly the pages that can’t be cached. If a big sale is coming up, go through our Black Friday checklist well ahead. We cover that and the rest of the PHP side, OPcache and the number of workers, in our guide to PHP optimization in WordPress.
More hosting isn’t always the answer. If one query spends several seconds in the database, a bigger server only makes it a little faster. Move only when the measurements show the server is the bottleneck.
Caching: what a store can cache and what it can’t
A page cache stores the finished page and sends it to the next visitor without running WordPress again. On a blog that covers almost every page view. In a store it doesn’t. Cart, checkout and My account are different for every customer and must never be cached, and as soon as a customer adds something to the cart, WooCommerce sets a cookie that many caching setups use to skip the cache for the rest of the visit. So the visitors closest to buying are the ones who get pages built from scratch. What can be cached and how to set it up is in our guide to WooCommerce caching.
A page cache is still worth having for product and category pages for new visitors. But what speeds up the rest is an object cache: an in-memory cache, usually Redis, that keeps the results of database queries between page views. It helps exactly the pages the page cache can’t cover. How to set one up is in our guide to Redis object cache. We compared the most used object cache plugins in a benchmark of object cache plugins for WooCommerce.
Also check that your cache actually works. Many caching plugins add a header or a comment in the page source when the page came from the cache. If it isn’t there on an ordinary product page, the cache is set up wrong.
The database: orders, postmeta and autoload
The database is a layer that often makes a store slower over time, because it grows with every order, every customer and every plugin. Four places are worth checking first.
Orders in wp_postmeta. In older WooCommerce stores, orders are stored as posts, and all their details sit as rows in wp_postmeta, the same table that holds the extra fields of products and everything else. With many orders the table gets large, and the admin orders list, reports and search slow down. That’s why WooCommerce has High-Performance Order Storage (HPOS), which keeps orders in their own tables. It has been the default for new stores since WooCommerce 8.2, but older stores have to switch themselves. Check which order storage your store uses under WooCommerce → Settings → Advanced → Features. What HPOS changes is covered in our guide to HPOS, and how to switch in migrating to HPOS without downtime.
Autoloaded options. WordPress loads every setting marked as autoload on every single page view. Plugins that store large amounts of data there, or that were uninstalled without cleaning up, make every page a little heavier. The Site Health page under Tools warns you when they take up a lot of space. How to find and remove them is in our guide to autoloaded options.
Heavy queries. Filters on color, size or price and custom sort orders often turn into queries that read all of wp_postmeta. With a few hundred products nobody notices. With many thousands it becomes seconds. Query Monitor shows which queries they are and which plugin runs them.
Data that grows by itself. Sessions in wp_woocommerce_sessions, expired transients, old revisions and log tables from plugins. Each one is a small problem, but they add up.
We go through how to find and fix each of these in our guide to making the WordPress database fast.
Background jobs: Action Scheduler, WP-Cron and admin-ajax
Much of what a store does doesn’t happen when the customer clicks, but afterward: order emails, stock updates, syncing with accounting or shipping, webhooks. WooCommerce puts those tasks in a queue, Action Scheduler, and runs them in the background. That works as long as the queue keeps getting emptied. If a job fails again and again, or more jobs come in than get processed, the tables grow and every run gets heavier. You’ll find the queue under WooCommerce → Status → Scheduled Actions. Many thousands of pending or failed actions are a sign that something needs attention. How to find the cause and get the queue moving again is in our guide to Action Scheduler.
By default the queue is triggered by WP-Cron, and WP-Cron runs when someone visits the site. On a busy store that means background jobs run on top of ordinary page views. On a quiet store it means they get delayed. Both are solved by having the server run WP-Cron on a fixed schedule instead of waiting for visitors. Many hosting providers can set that up.
In the admin there’s a third source: admin-ajax.php. The WordPress Heartbeat API and many plugins send requests to it at regular intervals for as long as an admin window is open. If several people keep the admin open all day, that alone can give the server noticeable work.
Plugins and theme
The number of plugins doesn’t say much. One plugin that runs a heavy query on every page view costs more than twenty small ones that only do something where they’re needed. What you want to know is what each plugin does on the page that’s slow.
Query Monitor shows this under “Queries by Component”, where queries are grouped by plugin and theme. If one plugin accounts for a large share of the time, you have a suspect. If you can’t see it there, deactivate plugins one at a time on a copy of the store and measure the page again after each. Never do it on the live store: a deactivated plugin can stop payments or orders. The full method is in our guide to finding the plugin that slows your site down.
The usual suspects are plugins that add features to every product view (filters, related products, “customers also bought”), statistics and logging plugins that write to the database on every page view, and page builders or themes that load a lot even on pages where it isn’t used.
Frontend: images, scripts and cart fragments
If TTFB is low but the page still takes long to become usable, the time is spent in the browser. In stores it’s often three things: large product images that aren’t resized or lazy-loaded, third-party scripts (tracking, chat, reviews, newsletter pop-ups) that each fetch code from other servers, and JavaScript from plugins that loads on every page.
One WooCommerce-specific item is cart fragments: a script that asks the server for the cart contents after the page loads, so the mini cart in the header stays current, even on a cached page. That’s one extra request, which can’t be cached, on every page view. Since WooCommerce 7.8 the script is no longer loaded on every page by default, but many themes and plugins turn it back on. You’ll see it in the Network tab as ?wc-ajax=get_refreshed_fragments. How to tell whether it costs you time, and what to do about it, is in our guide to slow add to cart and cart fragments.
We cover images, CSS, JavaScript and fonts in our guide to faster images, CSS and JavaScript in WordPress.
The order we’d work in
- Write down which pages are slow, and for whom.
- Measure TTFB on those pages without the cache, and run them through PageSpeed Insights.
- Check the PHP version, the memory limit and whether the server runs out of processes at busy times.
- Check that the page cache works on product and category pages, and consider an object cache.
- Find the slowest queries and the plugin behind them with Query Monitor on a copy.
- Look at order storage (HPOS), autoloaded options and the scheduled actions queue.
- Finally the frontend: images, scripts and cart fragments.
Fix one thing at a time and measure again after each. If you fix five things at once, you won’t know which one helped, or which one made something worse.
Frequently asked questions
Is WooCommerce just slow?
No. WooCommerce does more work per page view than a simple website, because the cart, prices and stock have to be right for every customer. But a store with sensible hosting, a page cache and an object cache, and without heavy plugins, can be fast. When it isn’t, there’s a cause that can be found.
Will more expensive hosting help?
Only if the server is the bottleneck. If the measurements show the time goes into one heavy query or one plugin, a bigger server makes it only a little better. Measure first, then move if it’s the server.
How many plugins is too many?
There’s no number. What counts is what each plugin does on each page view. Remove the ones you don’t use, and measure the ones you’re unsure about.
Want help?
Troubleshooting takes time, especially when the cause sits in a plugin or in data that has grown for years. If you’d rather have us find it, read about speed optimization for your WooCommerce store. We take a free look at your store first and tell you what it will take.