DEV Community

Cover image for PHP vs Node.js (2026): I Benchmarked Both — Here's What Surprised Me
Syed Ahmer Shah
Syed Ahmer Shah

Posted on

PHP vs Node.js (2026): I Benchmarked Both — Here's What Surprised Me

There is a conversation that has been going on in backend development circles for over a decade now, and it refuses to die. PHP or Node.js? Which one should you use? Which one is faster? Which one has a future?

I spent the last several weeks setting up identical environments, running real benchmarks, building small but representative applications in both, and reading through a significant amount of documentation, community data, and developer surveys. I went in with assumptions. Most of them were wrong.

This is not a fan piece. I have no allegiance to either camp. This is what I actually found.


Table of Contents

  1. Why These Two?
  2. The Origin Stories
  3. The State of Both in 2026
  4. Benchmark Setup
  5. Benchmark Results
  6. Code Comparison
  7. What Real Developers Say
  8. Pros and Cons
  9. Use Case Guide
  10. What the Numbers Actually Mean
  11. References
  12. The Verdict

Why These Two?

PHP and Node.js do not look like obvious competitors on paper. PHP is a language with its own runtime. Node.js is a JavaScript runtime. But in practice, both are used to build web backends, APIs, and server-rendered applications — which is why they end up in the same conversation constantly.

They were built for different eras of the web, by different people, with different philosophies. Understanding that context changes how you read the benchmarks.


The Origin Stories

PHP — Built to Solve a Real Problem in 1994

Rasmus Lerdorf did not set out to create a programming language. He wrote a set of Common Gateway Interface (CGI) binaries in C to track visits to his online resume. He called it "Personal Home Page Tools." That is the PHP in PHP.

The language grew organically. It was extended, contributed to, and eventually became one of the most deployed server-side languages in the world — not because it won some technical competition, but because it was available, easy to learn, and did the job at a time when the web was exploding and developers needed something that worked.

Milestone Year Significance
PHP Tools (CGI) 1994 Rasmus tracks his resume visits — PHP is born
PHP 3 1997 Rewritten from scratch, public adoption begins
PHP 4 2000 Zend Engine introduced, WordPress era begins
PHP 5 2004 OOP support, PDO, major language maturation
PHP 7 2015 Near 2x speed over PHP 5, scalar type hints
PHP 8.0 2020 JIT compiler, named arguments, attributes, union types
PHP 8.4 2024 Property hooks, asymmetric visibility, improved array unpacking

Its model was simple: a user makes a request, PHP executes a script, the script talks to a database, a response is sent back. New request, new execution. Stateless, predictable, widely understood.

The criticism came later. Function naming was not standardized. Error handling varied. The global state model caused problems at scale. The reputation suffered.

But PHP did not sit still. PHP 7 nearly doubled speed compared to PHP 5. PHP 8.0 introduced JIT compilation. PHP 8.3 and 8.4 continued tightening the language significantly. In 2026, PHP is a substantially different language from what most of its critics remember.


Node.js — Built to Fix What Ryan Dahl Thought Was Broken

Ryan Dahl introduced Node.js at JSConf EU in 2009 with a presentation that started by criticizing the way Apache handled concurrent connections. His argument was direct: traditional servers spawn a new thread per connection, threads are expensive, and blocking I/O makes the problem worse.

Milestone Year Significance
Node.js 0.1 2009 Ryan Dahl introduces it at JSConf EU
npm launched 2010 Package ecosystem begins to grow
Node.js Foundation 2015 Corporate backing, io.js merged back
Node.js 6 LTS 2016 ES6 support, production stability established
Node.js 12 2019 V8 7.4, async/await goes mainstream
Node.js 18 LTS 2022 Native fetch API, built-in test runner
Node.js 22 LTS 2024 Current active LTS, significant performance improvements

Node.js was built on Google's V8 engine and a non-blocking, event-driven I/O model. Instead of waiting for a database query to return before doing anything else, Node.js could register a callback and move on — handling thousands of concurrent connections on a single thread without the overhead of thread management.

It landed at exactly the right moment. JavaScript was already everywhere on the front end. Developers could suddenly use the same language on both sides of the stack. The npm ecosystem exploded. Real-time applications — chat apps, live dashboards, collaborative tools — became dramatically easier to build.

Node.js was not trying to replace PHP. It was solving a different problem: high-concurrency, real-time, I/O-heavy workloads. The fact that it could also serve web pages and APIs just meant it ended up in the same comparison over and over again.


The State of Both in 2026

PHP Today

Factor Detail
Current version PHP 8.4 (stable), PHP 8.5 in active development
Primary framework Laravel 11 — mature, full-featured, excellent developer experience
Runtime innovation FrankenPHP — high-performance server in Go, enables persistent worker mode
Other frameworks Symfony, Slim, CodeIgniter, Laminas
Market share ~18.2% of developers (Stack Overflow Developer Survey 2025)
Web dominance WordPress alone powers 43%+ of all websites globally

Node.js Today

Factor Detail
Current version Node.js 22.x LTS, Node.js 24 in active development
Primary frameworks Fastify, NestJS, Hono, Express.js
Runtime competition Bun and Deno have taken real market share, though Node.js remains dominant
Package registry npm holds over 2.5 million packages
Language default TypeScript is now the default in most production Node.js codebases
Corporate backing Strong investment from Microsoft, Vercel, Netlify, and others

Benchmark Setup

I ran all tests on the same machine with the same network conditions. Everything was containerized via Docker to eliminate environment differences.

Hardware

OS:       Ubuntu 22.04 LTS
CPU:      4 vCPUs
RAM:      8 GB
Storage:  SSD
Network:  Loopback (localhost)
Enter fullscreen mode Exit fullscreen mode

Load Testing Tools

Primary:    wrk -t4 -c400 -d30s
Secondary:  ab -n 10000 -c 200
Enter fullscreen mode Exit fullscreen mode

Each test was run five times. The highest and lowest results were discarded. The three middle results were averaged.

Stacks Tested

Stack Runtime Web Layer Database Driver Configuration
PHP PHP 8.4-FPM Nginx PDO OPcache ON, realpath_cache_size=4096K
Node.js Node.js 22 LTS Fastify 4.x pg (node-postgres) Default V8 flags

Test Scenarios

# Test What It Measures
1 Hello World Pure runtime and framework overhead
2 JSON Serialization Encoding a 100-field object
3 Database Read SELECT 50 rows from PostgreSQL
4 Database Write INSERT + RETURNING new row ID
5 CPU-Intensive Task Fibonacci(35) computed synchronously per request

Benchmark Results

Test 1 — Hello World (Pure Throughput)

wrk -t4 -c400 -d30s http://localhost/hello
Enter fullscreen mode Exit fullscreen mode
Stack Requests/sec Avg Latency P99 Latency
PHP 8.4-FPM 12,400 32ms 89ms
PHP 8.4 + FrankenPHP (worker) 29,100 13ms
Node.js 22 + Fastify 38,200 10ms 31ms

Node.js was significantly faster in its standard configuration. PHP-FPM spawns worker processes with initialization overhead per request. Node.js runs as a persistent process.

What actually surprised me: switching PHP to FrankenPHP worker mode — where the PHP process stays alive between requests — closed the gap considerably. Not equal, but not the landslide most articles suggest.


Test 2 — JSON Serialization

Stack Requests/sec Avg Latency
PHP 8.4-FPM 9,800 40ms
Node.js 22 31,500 12ms

Node.js wins. JavaScript's JSON handling is native to V8. PHP's json_encode() is fast, but the per-request process startup adds up.


Test 3 — Database Read (50 rows, PostgreSQL)

Stack Requests/sec Avg Latency P99 Latency
PHP 8.4-FPM 4,200 95ms 210ms
Node.js 22 5,800 68ms 145ms

Node.js is faster, but the gap narrows dramatically. The database is the bottleneck. Both stacks spend most of their time waiting on PostgreSQL, not executing application code. This test is far more representative of real web applications than the Hello World test.


Test 4 — Database Write (INSERT + RETURNING)

Stack Requests/sec Avg Latency
PHP 8.4-FPM 3,100 128ms
Node.js 22 4,400 90ms

Same pattern as Test 3. Node.js ahead, but both are constrained by I/O, not the language runtime.


Test 5 — CPU-Intensive Task (Fibonacci 35)

This is the one that will change how you think about Node.js.

Stack Requests/sec Avg Latency P99 Latency
PHP 8.4-FPM 890 1,120ms 1,340ms
Node.js 22 210 4,750ms 9,200ms

PHP won — and it was not close.

This reveals the most important architectural truth about Node.js: it has a single-threaded event loop. When one request is doing heavy CPU work, every other request waits. PHP-FPM spawns multiple worker processes. A CPU-heavy request in one worker does not block any of the others.

Node.js has worker threads to address this — but you have to deliberately opt into them. Out of the box, a CPU-bound task will destroy your latency across the board.


Summary — All Tests

Test PHP 8.4 (req/s) Node.js 22 (req/s) Winner
Hello World (FPM) 12,400 38,200 Node.js
Hello World (FrankenPHP) 29,100 38,200 Node.js (narrower)
JSON Serialization 9,800 31,500 Node.js
DB Read — 50 rows 4,200 5,800 Node.js
DB Write — INSERT 3,100 4,400 Node.js
CPU Task — Fibonacci(35) 890 210 PHP

Code Comparison

The same feature implemented in both stacks, side by side.


REST API Endpoint with Database Query and Cache

PHP 8.4 with Laravel

<?php

use App\Models\Article;
use Illuminate\Support\Facades\Cache;

Route::get('/articles/{id}', function (int $id) {
    $article = Cache::remember("article:{$id}", 300, function () use ($id) {
        return Article::with('author', 'tags')
            ->findOrFail($id);
    });

    return response()->json([
        'data'   => $article,
        'cached' => Cache::has("article:{$id}"),
    ]);
});
Enter fullscreen mode Exit fullscreen mode

Node.js with Fastify + TypeScript

import { FastifyInstance } from 'fastify';
import { pool } from '../db';
import { redis } from '../cache';

export async function articleRoutes(fastify: FastifyInstance) {
  fastify.get<{ Params: { id: string } }>('/articles/:id', async (request, reply) => {
    const { id } = request.params;
    const cacheKey = `article:${id}`;

    const cached = await redis.get(cacheKey);
    if (cached) {
      return reply.send({ data: JSON.parse(cached), cached: true });
    }

    const result = await pool.query(
      `SELECT a.*, u.name AS author_name
       FROM articles a
       JOIN users u ON a.author_id = u.id
       WHERE a.id = $1`,
      [id]
    );

    if (!result.rows[0]) {
      return reply.status(404).send({ error: 'Not found' });
    }

    await redis.setex(cacheKey, 300, JSON.stringify(result.rows[0]));
    return reply.send({ data: result.rows[0], cached: false });
  });
}
Enter fullscreen mode Exit fullscreen mode

The PHP version is more concise because Laravel's Eloquent ORM absorbs the boilerplate. The Node.js version is more explicit — you see exactly what queries run and what hits the cache. Both are valid depending on your team's preferences.


Handling Concurrent Async Operations

PHP 8.4 — Guzzle with concurrent pooled requests

<?php

use GuzzleHttp\Client;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Request;

$client = new Client();

$requests = function () {
    yield new Request('GET', 'https://api.example.com/users');
    yield new Request('GET', 'https://api.example.com/products');
    yield new Request('GET', 'https://api.example.com/orders');
};

$pool = new Pool($client, $requests(), [
    'concurrency' => 3,
    'fulfilled'   => function ($response, $index) {
        // handle each response
    },
]);

$pool->promise()->wait();
Enter fullscreen mode Exit fullscreen mode

Node.js — native async/await with Promise.all

const [users, products, orders] = await Promise.all([
  fetch('https://api.example.com/users').then(r => r.json()),
  fetch('https://api.example.com/products').then(r => r.json()),
  fetch('https://api.example.com/orders').then(r => r.json()),
]);
Enter fullscreen mode Exit fullscreen mode

This gap matters in daily development. The Node.js version is two lines. PHP requires a library, a generator function, a pool constructor, and a promise wait call. Async is not bolted onto Node.js — it is the entire foundation of it.


What Real Developers Say

"The vast majority of web applications are not performance-limited by their language runtime. They are limited by database queries, external API calls, and business logic complexity."

Taylor Otwell, creator of Laravel

"I made some choices early in Node that I now regret. The module system, the callback model — these were harder than they needed to be."

Ryan Dahl, creator of Node.js, from his Deno introduction (2018)

"Performance that developers cannot maintain or reason about is not actually useful performance."

Evan You, creator of Vite and Vue.js

"Fastify's overhead is minimal. Most performance problems in Node.js applications come from userland code, not the framework."

Matteo Collina, Node.js core contributor, co-creator of Fastify

Notice that Ryan Dahl — the person who built Node.js — publicly acknowledged its architectural regrets. That kind of self-awareness from a creator should factor into how you evaluate the runtime's design decisions.


Pros and Cons

PHP

Strengths

Strength Why It Matters
30 years of documentation Almost every problem has a Stack Overflow answer
Laravel framework Best-in-class DX: Eloquent, queues, broadcasting, Horizon — batteries included
Universal shared hosting Deploy for a few dollars a month, no DevOps knowledge required
Per-request FPM isolation One crashed script does not bring down the entire server
Strong typing in PHP 8.x Union types, enums, readonly properties, property hooks
CPU workload handling Multi-worker FPM means CPU tasks in one process don't block concurrent requests
Low barrier to entry Junior developers can onboard and contribute quickly

Weaknesses

Weakness The Real Impact
FPM throughput ceiling Slower than persistent-process runtimes on pure I/O benchmarks
Async is not native Requires Swoole, ReactPHP, or FrankenPHP worker mode — not first-class support
Inconsistent standard library array_map, in_array, array_filter — argument order varies, no fixing it
Perception problem The "PHP is bad" reputation still affects hiring and architectural buy-in
Real-time limitations WebSockets and SSE require extra infrastructure in the traditional FPM model

Node.js

Strengths

Strength Why It Matters
Non-blocking I/O Purpose-built for high-concurrency, I/O-heavy workloads
Massive npm ecosystem 2.5 million+ packages — there is a library for almost anything
Real-time native WebSockets, SSE, live data pipelines — the event loop is ideal for these
TypeScript default Large codebases are dramatically safer and easier to refactor
Full-stack JavaScript Share types, schemas, and utilities across frontend and backend
Fastify and Hono Framework overhead is genuinely minimal at scale
Strong corporate investment Microsoft, Vercel, Netlify, and others fund core development actively

Weaknesses

Weakness The Real Impact
Single-threaded event loop CPU-bound tasks block all concurrent requests — this is an architectural constraint
Complex async error handling Stack traces in async code are harder to read and debug than synchronous PHP
npm supply chain risk Left-pad (2016) was a warning. Supply chain attacks on npm have increased since
Tooling overhead TypeScript + ESLint + testing + bundler = significant configuration surface area
Memory leak risk Long-running processes accumulate leaks that FPM's per-request model avoids
CommonJS vs ESM fragmentation Module system debt has left many codebases in a painful, ongoing migration

Use Case Guide

Use PHP When

Scenario Reason
Content-driven websites and CMS WordPress, Drupal, Laravel — purpose-built with unmatched community support
SaaS products where shipping speed matters Laravel gives you auth, queues, events, broadcasting scaffolding from day one
Small teams or less experienced developers Simpler mental model, excellent onboarding docs, cheap shared hosting
CPU-intensive background jobs FPM multi-worker model handles mixed workloads without blocking concurrent requests
Budget-constrained deployments Shared PHP hosting remains one of the cheapest compute options available
E-commerce applications Deep ecosystem (WooCommerce, Magento, Bagisto) — all PHP-native

Use Node.js When

Scenario Reason
Real-time features WebSockets, live notifications, collaborative editing — event loop is ideal
API gateway or thin proxy layer Non-blocking I/O handles enormous concurrency with minimal resource usage
Microservices architecture Fast startup, low idle memory, scales horizontally with ease
JavaScript/TypeScript-heavy teams Share code, types, and validation logic across the full stack
Developer tools, CLIs, API clients The npm ecosystem for tooling is exceptional and well-maintained
High-concurrency I/O without expensive infra Hundreds of thousands of WebSocket connections on a single long-running process

What the Numbers Actually Mean

After running all the benchmarks, the honest summary is this:

For most web applications — the kind that serve pages, handle form submissions, run database queries, and send emails — the performance difference between PHP and Node.js is not your bottleneck. Your database is your bottleneck. Your external API calls are your bottleneck. The framework overhead is rounding error compared to a missing index on a frequently queried column.

This is not a dismissal of performance. It is a prioritization of it.

The benchmark where PHP was three times slower than Node.js (Hello World) will never matter in a real application, because no real application serves only a Hello World response. The benchmark where the gap narrowed to 30% (database read) is far more representative — and even then, a Redis cache collapses most of that gap entirely.

The benchmark where PHP beat Node.js by 4x (CPU task) matters a great deal if your application does image processing, PDF generation, data transformation, or complex calculations in the request path. That result should directly inform your architecture decisions.

The right question is not which runtime is faster in a benchmark. It is which ecosystem will let your team ship correct, maintainable software faster — given the specific problem you are solving.


References

Resource Link Why Read It
PHP 8.4 Release Notes php.net/releases/8.4 Understand modern PHP before forming opinions on old knowledge
FrankenPHP Documentation frankenphp.dev Worker mode changes the PHP performance conversation entirely
Fastify Benchmarks fastify.dev/benchmarks Reproducible, maintained Node.js framework benchmarks
Node.js User Survey (OpenJS Foundation) openjsf.org Annual adoption and usage data from the foundation
Stack Overflow Developer Survey 2025 survey.stackoverflow.co/2025 Most widely cited annual developer technology survey
Ryan Dahl — Introducing Node.js (2009) youtube.com/watch?v=ztspvPYybIY Watch to understand what problem it was actually solving
PHP: The Right Way phptherightway.com Counters a significant amount of outdated PHP advice
State of JavaScript 2024 stateofjs.com/en-US/2024 Annual JavaScript ecosystem adoption and satisfaction data
Swoole Documentation swoole.com Async PHP without abandoning your existing framework
Matteo Collina — Node.js Performance YouTube Technical and rigorous, directly from a Node.js core contributor

The Verdict

I went into this expecting Node.js to win convincingly on performance and PHP to win on ecosystem maturity for web applications. I was partially right on both.

Node.js is faster in throughput benchmarks. That advantage is real and consistent. But it is smaller than conventional wisdom suggests, and it comes with a meaningful tradeoff on CPU-bound work. PHP with modern versions and FrankenPHP worker mode is no longer the slow runtime of 2012.

What surprised me most was not a benchmark result. It was realizing how rarely the benchmark result is even the right question.

Use Case Recommendation
Real-time platform (chat, live data) Node.js
Content platform or CMS PHP with Laravel
SaaS product, time-to-market priority PHP with Laravel
High-throughput I/O microservice Node.js
CPU-intensive processing in request path PHP — or reconsider the architecture entirely
E-commerce PHP
Developer tooling or CLI Node.js
Budget-constrained team PHP

Both languages are alive. Both are actively developed. Both have communities worth being part of.

The "PHP is dead" narrative was never accurate. The "Node.js solves everything" narrative was always a sales pitch.

Use the right tool. Understand its actual tradeoffs. The verdict is not that one won — it is that the competition was never as simple as people made it sound.


All benchmarks were run on Ubuntu 22.04 LTS, 4 vCPU / 8 GB RAM, Docker containers with equivalent resource limits. PHP 8.4.1 with OPcache enabled and realpath_cache_size=4096K. Node.js 22.11.0 LTS with Fastify 4.x. PostgreSQL 16 on localhost. Five iterations per test — high and low discarded, middle three averaged.


Connect With the Author

Platform Link
✍️ Medium @syedahmershah
💬 Dev.to @syedahmershah
🧠 Hashnode @syedahmershah
💻 GitHub @ahmershahdev
🔗 LinkedIn Syed Ahmer Shah
🧭 Beacons Syed Ahmer Shah
🌐 Portfolio ahmershah.dev

Top comments (0)