Skip to content

Case study Original Research

PHP benchmarks across major CMSs and frameworks

I rebuilt how Kinsta measured PHP performance, then ran the benchmark for two years. Across those two editions I built 34 test setups, documented every page I tested, ran every benchmark myself, and published 143 scores. The parameters I set in 2021 are the ones the current edition still runs on.

Read the story

Client
Kinsta
Role
Researcher / Technical Writer
Year
2021 and 2022
Disciplines
Test design, Benchmarking, Data analysis

Proof at a glance

The scale of the work


Both reports are archived with my byline. I ran a third round on PHP 8.2 that Kinsta never published.

  • 143

    Benchmark scores

    Published across the 2021 and 2022 reports. Every one is in the dataset at the foot of this page.

  • 34

    Platform setups

    Built, configured and tested. 20 in 2021, 14 in 2022.

  • 5 years

    Still running

    Kinsta has published the benchmark every year since. The December 2025 edition runs on the parameters I set.

The problem

Old PHP is a bill the site owner pays every month

The WordPress 5.9 RC2 benchmark from the 2022 reportSource: Kinsta

A site on an old PHP version serves fewer requests per second on the same hardware. So it needs more server to carry the same traffic. It gets slower for the visitors it already has. And once that version goes end of life, it stops receiving security patches at all.

The owner pays in hosting spend. The host pays in support load. That is why Kinsta’s marketing and sales teams published a PHP benchmark every year, on one article rewritten each time, and it had been running for years before I joined.

When I took the series over in early 2021, W3Techs had 38.9% of all PHP sites still on 5.6 or lower, and WordPress.org’s own stats showed only 49.9% of WordPress sites on a supported PHP version. Kinsta had been telling those owners to upgrade for years. The benchmark gave them a number to look at.

The comparison problem

The easy version of this test tells the reader nothing

Rank all 20 platforms by requests per second and publish the chart with WordPress next to Laravel. I didn’t run that test. A WordPress home page, a WooCommerce product page and a small Laravel app do different amounts of work, so the top of that chart only tells you which page is lightest.

Every other decision in the method follows from one question, and I wrote the boundary into both reports in plain words: these results show how a platform competes against itself across PHP versions, and they shouldn’t be used to weigh one platform against another.

What had to stay the same

  • The application version and its content
  • The tested page, recorded element by element
  • The machine, web server, database and every setting

What I changed

The article existed. I rebuilt how it was measured.

Thoriq Firdaus had run the 2020 edition across 22 configurations, and he walked me through it when I took over. I read it the way I’d read any benchmark, by asking what I’d have to trust to believe the numbers.

Changing how the load worked mattered most. Run a page for a minute and you measure whatever the machine got through in that minute, so if I ran the same test a year later I’d have no way of knowing whether the two runs did the same amount of work. Sending a fixed 10,000 requests takes that question away. I didn’t know it would become a standard. I was trying to build the best benchmark I could inside the few weeks each edition got, so a reader could check my work instead of taking my word for it.

2020 method, then mine

Load
2020 method The home page for one minute mine a fixed 10,000 and later 1,000 requests, both at 15 concurrent users
Content
2020 method Fresh barebone installs mine official demo content for every platform
Page evidence
2020 method Platform logos mine a screenshot of every tested page with its size in bytes
Documentation
2020 method A line or two mine element by element so the page could be matched a year later
Boundary
2020 method Barebone installs noted mine readers told not to rank platforms against each other
Replication
2020 method None stated mine repeated runs with the top three averaged from 2022

The approach

Everything except PHP had to stay the same

Inside an edition, the application version, the content, the tested page, the machine, the web server, the database and every configuration value stayed fixed. PHP was the only variable. That sounds obvious written down, and it is the reason most of the work in this project happened before a single benchmark ran.

  1. Compare each platform only against itself

    I treated every platform as its own test. WordPress against WordPress across PHP versions, Drupal against Drupal, Laravel against Laravel.

    I picked one page per platform and wrote down what was on it, so each number stayed tied to a known page and no chart could read as a ranking between unrelated systems.

    Decision

    Read across PHP versions within one platform. Never across platforms.

  2. Build a page worth testing on all 20 platforms

    I had to build 20 installations, each one rebuildable a year later and comparable to itself. Installing them was the quick part. Working out what belonged on each page took far longer.

    Some platforms came with a demo site, so the work was choosing which page to test. Drupal came with Umami, a food magazine, and I tested an article page from it. Craft, Kirby, Symfony, concrete5 and PyroCMS all came with starter content I could use as installed.

    The two stores needed their products brought in. For WooCommerce I installed the Storefront theme and imported the official sample products, then tested a single product page that loads an image, a description, an add-to-cart button, reviews, sidebar widgets, a related-products block and a pullout widget. For Easy Digital Downloads I installed Themedd and its demo content, then tested a download page with an image, a description, a purchase button and some category links. Two WordPress product pages, and one does several times the work of the other. This is why a leaderboard would have been useless.

    Laravel, CodeIgniter and CakePHP open to a welcome screen, which is a sensible thing for a framework to do and an unhelpful one for a benchmark. There was no page until I built one. For Laravel I built a small app against a database of 1,000 posts, for CodeIgniter a news table of 1,000 rows, and for CakePHP a list of 400 generated posts. I published those schemas in the report so a reader could rebuild the test instead of trusting my numbers.

    Then I wrote down every tested page element by element. That record is what let me install a newer version in 2022 and know I was measuring the same kind of page. No single platform was a disaster. The frameworks took the most fiddling, and that was about the same work as setting up the two stores with their products imported. I’m going through all of this to drive the point home that most of a benchmark happens before it runs.

    What each kind needed

    Came with a demo site
    Pick a page, record it
    Opened to a welcome screen
    Build content first
    Ecommerce
    Import the product set
    Framework
    Build an app first
  3. Hold the environment still

    Every setup ran on the same Google Cloud machine, an Intel Xeon with 30 cores and 120GB of RAM in an isolated container, on Ubuntu 20.04 with Nginx and MariaDB. I kept the application, the content, the tested page and every server setting fixed while switching PHP versions.

    Full-page caching stayed off. A cached page never reaches PHP, and a benchmark where PHP does no work measures nothing.

    OPcache stayed on. It stores precompiled bytecode in shared memory, so PHP stops reparsing scripts on every request. Every properly configured PHP server has it enabled, and turning it off would have measured a setup that doesn’t exist in production.

    I raised opcache.max_accelerated_files from 4000 to 50000 so the larger platforms wouldn’t hit the cache limit. Every other value stayed at the recommended default, so the one deliberate change from stock is documented in the report.

    Test conditions

    Machine
    Xeon 30-core, 120GB RAM
    Page cache
    Off
    OPcache
    On, one setting raised
  4. Warm up first, then measure twice

    I ran warm-ups on every setup before recording anything. A cold PHP process with an empty OPcache answers the first requests slowly, and measuring that tells you about startup. The warm-ups never appeared in the published reports, which is one of the things I’d change.

    Then ApacheBench sent a fixed workload at 15 concurrent users and I recorded requests per second. I ran each benchmark several times to catch results that moved between runs, and from 2022 I tightened that into a stated rule, averaging only the top three.

    Load test

    2021
    10,000 total requests
    2022
    1,000 total requests

    15 concurrent users in both editions

  5. Publish the results that argued against the article

    Drupal 9.1 was the first one. It scored 363.06 req/sec on PHP 7.3, 328.08 on 7.4 and 304.07 on 8.0. Newer PHP was slower, on the flagship CMS of the report, in a series whose entire purpose was convincing people to upgrade.

    So I ran it again. Then I tore the Drupal install down and built it from scratch. The third run gave the same answer, so it went into the report with a note saying the result was strange and that later Drupal versions might behave differently.

    That one got written up as the surprise of 2021. Going back through the full dataset for this page, it wasn’t a surprise at all. A newer PHP version scored lower than the version before it in 20 places across the series, on 15 of the 34 setups. I published every one of those 20 numbers, with the percentages worked out so a reader could see how big each drop was.

    Where a platform couldn’t run on a PHP version at all, I recorded it as unsupported and invented no number for it. 67 of the 210 cells in the series have no score for that reason. So when you see a blank in the chart, you know the platform couldn’t run that version. Leave those out and an incompatible combination starts looking like a slow one.

    Drupal 9.1, 2021

    PHP 7.3
    363.06 req/sec
    PHP 7.4
    328.08 req/sec
    PHP 8.0
    304.07 req/sec

    Rebuilt from scratch, run three times, published as found

  6. Work out every percentage for the reader

    Every successful test needed the platform, its release, the PHP version, the tested page, the value and the unit before it went anywhere. I organized and labelled all of it, then handed it to Kinsta’s graphics team, who built the two combined charts from what I supplied.

    I worked out every percentage in the article, so a reader doesn’t have to do arithmetic off a chart to find out what an upgrade buys them.

    Data handoff

    • Platform and release
    • PHP version
    • Test page
    • Value and unit
    • Support status

The results

The newest PHP won most of the time, and I said how often

2021
PHP 8.0 was the fastest in 7 of the 10 setups that could run it Drupal, CakePHP and Pico went to an older version, and all three kept their result. Stock WordPress went from 123.52 req/sec on PHP 5.6 to 233.40 on 8.0, 18.47% faster than 7.4.
2022
PHP 8.1 was the fastest in 9 of the 11 setups that could run it WordPress 5.9 RC2 moved from 111.10 req/sec on PHP 8.0 to 163.43 on 8.1, a 47.10% jump. The four versions below it were within 5 req/sec of each other.
Regressions
20 of the 143 published scores went backwards The PHP 7.0 to 7.1 step went backwards on 7 setups in a row. The largest drop in either edition was Laravel, down 15.7% from PHP 8.0 to 8.1 in 2022. All 20 were published.
Reuse
Cited, carried in newsletters, and used in other people’s decisions Post Status, AgileDrop and PHP Weekly picked it up. A GitHub issue used the benchmarks to argue for PHP 8.3 support. A developer on daily.dev reached the same conclusion.

Kinsta published the PHP 8.5 edition in December 2025. It runs ApacheBench at 15 concurrent users and 1,000 requests, with a warm-up request before each test and five runs per configuration. OPcache is on, WordPress is still tested on 7.4 because so many sites run it, and a line says the results are not meant to compare the platforms against each other.

Those are the parameters I set in 2021 and 2022. I wrote that caveat so readers wouldn’t misread the chart, and it’s still in the article four years later, in a version of the test I had nothing to do with.

The published work

The two editions I ran and wrote

Kinsta updates one article URL for each new edition, so later benchmarks by other Kinsta authors have appeared on the live page since 2023. These links open the two editions I wrote.

  • Kinsta's cover artwork for the 2021 PHP benchmark report
    2021 / PHP 8.0 PHP Benchmarks for WordPress and Other Platforms 20 setups across 7 PHP versions, 5.6 through 8.0 Source: Kinsta Read the report
  • Kinsta's cover artwork for the 2022 PHP benchmark report
    2022 / PHP 8.1 PHP Benchmarks for WordPress and Other Platforms 14 setups across 5 PHP versions, 7.2 through 8.1 Source: Kinsta Read the report

The final proof

The charts, edition by edition


Each row compares one platform against itself across the PHP versions in that edition. Kinsta’s graphics team built every chart from the data I supplied.

  • 2021 / WordPress 5.6 WordPress 5.6 PHP benchmarks Source: Kinsta
  • 2021 / WooCommerce 4.8.0 WordPress 5.6 + WooCommerce 4.8.0 PHP benchmarks Source: Kinsta
  • 2021 / Drupal 9.1.0 Drupal 9.1.0 PHP benchmarks Source: Kinsta
  • 2021 / PHP 8.0 Every 2021 result in one chart. Rows compare a platform against itself. Source: Kinsta
  • 2022 / WooCommerce 6.1.1 WordPress 5.9-RC2 + WooCommerce 6.1.1 PHP Benchmarks. Source: Kinsta
  • 2022 / Drupal 9.3.3 Drupal 9.3.3 PHP Benchmarks. Source: Kinsta
  • 2022 / PHP 8.1 The 2022 series, five PHP versions across fourteen setups. Source: Kinsta

Distribution and reuse

The reports got cited and reused

These are the ones you can still click.

What I would change

Six things I would change, and three I got wrong

Something bothered me the whole time I was running these, and I never did anything about it. Every number in the series is relative to another number in the same row. Nothing in the test tells you what the server was capable of on its own.

So I’d add a control. A plain static PHP file, no application at all, benchmarked on the same machine under the same conditions. That tells a reader what the machine manages on its own, which is the number every other result should be read against. I never built it, and it’s the first thing I’d add now.

Next time
  • Publish the raw results as CSV or JSON, so nobody has to read them off a chart
  • Report the median and the range next to the headline figure
  • Check status codes, response bodies and response sizes automatically after every run
  • Save the setup and benchmark scripts and publish them with the report
  • Separate compatibility from speed in the result layout
What I got wrong
  • The 2022 CakePHP figure for PHP 7.3 is printed as 874.69.28 req/sec, which is not a number
  • The 2022 Craft CMS rows for PHP 7.2, 7.3 and 7.4 match the 2021 figures to two decimal places, so three of its five rows came from the previous year’s build
  • My framework test pages got lighter between editions. Laravel’s 2021 page read 1,000 posts from a database. By 2022 it was a page I described as not a full web application, which is why Laravel posts 2,376 req/sec that year

Five years on, I would rather find those myself than have a reader find them. The dataset is in the sources below.

Sources and credits

Where to check all of this

Credits

Client
Kinsta, marketing and sales teams
Previous edition
Thoriq Firdaus, who helped me take it over
Benchmarks and writing
Salman Ravoof
Final charts
Kinsta graphics team, from my data and labels
Archive
Internet Archive

Later editions by other Kinsta authors have appeared on the live URL since 2023. The two archive links above are the editions I wrote.