Ghost vs WordPress performance, load tested
Ghost 6 and WordPress 6.8 on the same server, both from their official images with MySQL 8.4, default config and no cache, serving the same 10 posts through their public posts API to the same 2,500 simulated users. This is two of the five CMSes from our CMS load test; the full report also covers Payload, Strapi and Directus.
Answered requests a second, p95 of answered requests, and failures as users ramped up
| Simulated users | Ghost 6 | WordPress 6.8 |
|---|---|---|
| Under 100 | 85 rps, p95 560 ms | 69 rps, p95 950 ms |
| About 250 | 115 rps, p95 3.3 s | 75 rps, p95 3.4 s, 8% timed out |
| About 500 | 113 rps, p95 6.8 s | 77 rps, p95 3.4 s, 29% timed out |
| About 1,000 | 116 rps, p95 9.9 s | 63 rps, 57% timed out |
| About 1,500 | All 429 Too Many Requests | 26 rps, 85% timed out |
| 2,400 to 2,500 | All 429 Too Many Requests | 64 rps, 78% timed out |
The setup
One fresh 4 vCPU / 8 GB server (shared vCPU) per run, with the CMS and MySQL 8.4 in one docker compose stack from the official images. Ghost served its Content API and WordPress its REST API, 10 posts per request from the same 10 posts. Load came from a second server in the same datacenter and ramped from zero to 2,500 simulated users over 10 minutes. Requests that took longer than 10 seconds count as timed out. The compose files are at github.com/DevMatei/stresix-showdowns.
The short answer
Ghost answered about 1.5 times as many requests a second as WordPress, using one core, while WordPress used all four. Then they failed in different ways. WordPress requests started timing out at about 250 users and most of them timed out from about 1,000. Ghost made requests wait longer and longer, and about 3.5 minutes in, near 1,200 users, it started answering 429 Too Many Requests to everything.
What ran out
WordPress was CPU bound in the plain sense: all 4 cores over 90% from about the first second, with the work spread across Apache and PHP workers, none of them above 5% of a core. Ghost was the opposite: one Node thread at 100% of a core while the server as a whole was about 37% busy. MySQL was not the limit for either, at about 0.5 cores under WordPress and 0.2 under Ghost.
About the 429s
Ghost rate limits by client address, and all load in a run comes from one load generator, so the limit trips far earlier than it would with real visitors spread across many addresses. Its Node thread was already at 100% before that, and p95 was close to the 10 second timeout, so it was near its ceiling either way.
Would a bigger server help?
For WordPress, yes in principle, because it really did use every core. The report sized it at 8 vCPU / 16 GB to comfortably serve about 100 requests a second, which is a lot of server for a 10 post API. The cheaper first step is a page or object cache, which this test left out on purpose. For Ghost, more cores would mostly sit idle. Ghost runs as one process per site, so a cache or CDN in front is the usual way to serve more traffic.
What this does not tell you
One read only API endpoint, 10 posts, no cache, one run each on shared vCPU. Most real Ghost and WordPress sites serve themed pages through a cache or CDN, so visitors rarely reach PHP or Node on every request. WordPress also returns more data per post by default. This compares the two engines with nothing in front of them, which is what you get on a fresh install.
Frequently asked questions
Is Ghost faster than WordPress?
In this test, yes. With no cache and default configs on the same server, Ghost served about 100 to 115 requests a second from its Content API on one core, and WordPress about 75 to 78 from its REST API using all four cores.
Why is WordPress slow under load?
Every uncached request runs PHP and loads WordPress. In this run that kept all 4 cores at 100% from the first second, and requests started timing out at about 250 users. A page cache or object cache is usually the first fix, before a bigger server.
Can Ghost use more than one CPU core?
One Ghost process runs its JavaScript on one thread, and in this run that thread hit 100% of a core while the server was about 37% busy. A cache or CDN in front is the usual way to take load off it.
Can I test my own site like this?
Yes. Point Stresix at a repo or compose file and it starts the stack on a fresh server, sends the load, and reports what ran out first. Your first run is free.
Related guides
Stop guessing your specs. Start knowing them.
Point Stresix at a repo or Docker image and get a number you can deploy on, in one run. Your first run is free, no card.
Start a free load test