Payload vs Strapi performance, load tested

Payload 3 and Strapi 5 on the same server, each with Postgres 17, default production config and the same 10 posts, with the same 2,500 simulated users sent at the list posts API. This is two of the five CMSes from our CMS load test; the full report also covers WordPress, Ghost and Directus.

Requests a second and p95 as users ramped up

Simulated usersPayload 3Strapi 5
Under 100324 rps, p95 160 ms206 rps, p95 240 ms
About 250492 rps, p95 640 ms287 rps, p95 1.1 s
About 500495 rps, p95 1.6 s290 rps, p95 2.0 s
About 1,000465 rps, p95 3.4 s286 rps, p95 4.1 s
About 1,500456 rps, p95 3.4 s286 rps, p95 6.8 s
2,400 to 2,500424 rps, p95 6.8 s279 rps, p95 9.9 s
Whole run217,142 answered, 0 errors133,269 answered, 0 errors

The setup

One fresh 4 vCPU / 8 GB server (shared vCPU) per run, with the CMS and Postgres 17 in one docker compose stack. Neither project ships an official image, so these are the stock create-strapi-app project and the Payload with-postgres template, both built in production mode. Both got the same 10 posts on first boot. Load came from a second server in the same datacenter and ramped from zero to 2,500 simulated users over 10 minutes, all requesting the list of posts. The compose files are at github.com/DevMatei/stresix-showdowns.

The short answer

Payload answered about 1.6 times as many requests as Strapi over the same run, and it was quicker at every load level. Neither returned a single error. Both stopped getting faster for the same reason: one Node thread at 100% of a core while most of the server sat idle.

Where each one topped out

Payload kept adding throughput until about 830 users, held around 490 requests a second, and slid to about 425 by the end as the queue grew. Strapi reached about 290 requests a second by 250 users and stayed flat from there. Past that point every extra user just waited longer, so its p95 climbed to almost 10 seconds, right at the timeout, without a request actually failing.

What ran out

The same thing for both. Payload 3 runs inside Next.js, and its Next.js server thread was pinned at 100% of a core from the start, with the server as a whole about 36% busy. Strapi's Node thread did the same at about 39%. Postgres used about 0.3 cores in both runs, and both apps used about 1 GB of memory, so neither the database nor memory was close to the limit.

Would a bigger server help either one?

Not by itself. Each used one core out of four, so more vCPUs would sit idle. The fix to try first is several processes on the same server, behind a proxy or load balancer. From what one process did here, the reports estimate that 4 processes on this server would comfortably serve about 770 requests a second for Payload and about 430 for Strapi. Those are estimates, not measurements, so measure again after the change.

What this does not tell you

One read only endpoint with 10 posts, one run each, on shared vCPU. Nothing here covers the admin panel, writes, auth, uploads, relations or large collections, and the default response shapes are not identical. p95 is averaged from the run's latency samples, so treat it as approximate. If one of the setups looks wrong, open an issue on the repo and it will be rerun.

Frequently asked questions

Is Payload faster than Strapi?

In this test, yes. Same server, same Postgres, default configs: Payload held about 490 requests a second on the list posts API and Strapi about 290, both with zero errors. Your own collections and queries can behave differently, so test your own setup before you pick on speed alone.

Why does Strapi only use one CPU core?

Node runs JavaScript on one thread per process, and a default Strapi install runs one process. In this run that thread hit 100% of a core while the server was about 39% busy. Running more than one process behind a load balancer lets it use the other cores.

Does Payload 3 run on Next.js?

Yes. Payload 3 installs into a Next.js app, and in this run the busiest thread was the Next.js server. That one thread was also what limited it.

Can I test my own Payload or Strapi app like this?

Yes. Point Stresix at your repo or compose file and it starts the app with its database on a fresh server, sends the load, and reports what ran out first, per service and per thread. 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