How We Reinvented PHP but 10x Slower: Why React Server Components Are a Dead End
A provocative comparison of React Server Components to classic PHP server rendering, arguing that RSC reintroduces the same paradigm with vastly more complexity, higher costs, and vendor lock-in.
Translation of an article by Danil Emelyanov (MrTheFirst)
Introduction: 4 Hours to Deploy a Content Site
The other day I dusted off a small pet project. A simple blog — surely each of you has at least thought about making one for yourself.
In 2015, I would have just uploaded files via FTP to a hosting plan for 100 rubles. Deploy time: 30 seconds.
In 2026, I spent 4 hours. I was configuring Edge Middleware, debugging HTML desynchronization between client and server (hydration mismatch), and figuring out why the cloud didn't want to cooperate with my database due to slow function wake-up (cold start).
Where did we go wrong? This is the wheel of Samsara making another revolution.
Remember the 2010s? Everyone wrote in PHP. How did it work?
- The browser requested a page.
- The server went to the database, glued together HTML, and sent it back.
- The user saw content immediately.
Then we said: "Ugh, page reloads are so last decade!" And we invented SPAs (Single Page Applications). We moved rendering to the browser, killed SEO, made phones overheat, but achieved smooth transitions.
Sixteen years have passed. And now they're selling us React Server Components (RSC). Let's face the truth. We've come back to PHP. But with one caveat.

Spot the 10 Differences
Let's do a blind test. First — PHP code from the 2010s. Then — cutting-edge Next.js code from 2026.
PHP (2010):
// index.php
// No configs. No build step. Just code.
$db = new SQLite3('products.db');
$result = $db->query('SELECT * FROM items');
?>
<ul>
<?php while ($row = $result->fetchArray()): ?>
<li><?= $row['name'] ?></li>
<?php endwhile; ?>
</ul>Next.js RSC (2026):
// page.tsx (Server Component)
// Dependencies: Node.js, Webpack, Babel, PostCSS...
import { db } from './db';
export default async function Page() {
const items = await db.query('SELECT * FROM items');
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}We're writing the same thing. The logic is identical. Server-side rendering. But there's a "caveat" in the infrastructure.
To run a PHP file, you need any shared hosting for 150 rubles. To run an RSC file, you need:
- A Node.js cluster.
- A CI/CD pipeline.
- A build system that separates code into "server" and "client."
- A data serialization process.
We built a spaceport to launch a paper airplane.
Benchmark: The Cost of "Hello World!"
Enough lyricism. Let's look at numbers. Take an empty application that simply renders <h1>Hello World</h1>.
PHP (v8.2):
- Bundle size: 0 KB (sends pure HTML).
- Time to Interactive (TTI): 50 ms.
- Memory consumption: 5 MB per process.
Next.js (v14, App Router):
- Bundle size (JS): 184 KB (React, React DOM, Next Runtime, Webpack runtime). (Even if you squeeze it with a minifier down to 80 KB, that's still 80 KB vs. 0 for PHP.)
- Time to Interactive (TTI): 350 ms (on mobile 4G).
- Memory consumption: 150 MB (Node.js process).
Why does the user need to download 184 kilobytes of JavaScript to see static text?
"But that's for future interactivity!" you'll say. That's a loan you're taking from the user without their consent. You're spending their bandwidth and battery on a potential capability that may never be needed.
Cascade of Requests: What Happens on the Network
PHP:
[Client] -> GET /index.php -> [Server]
[Client] <- HTML (2kb) <- [Server]
(Done. Browser renders.)RSC:
[Client] -> GET /page -> [Server]
[Client] <- HTML shell (Skeleton) <- [Server] (First paint)
[Client] -> GET /_next/static/chunks/main.js -> [Server]
[Client] -> GET /_next/static/chunks/app/page.js -> [Server]
[Client] -> GET /_next/data/.../page.rsc -> [Server]
[Client] (Hydration...)
(Done. Interactive.)
See the difference? We added 3 network requests and 200ms of latency for nothing. And this is for "Hello World." On a real project, the waterfall turns into Niagara Falls.
The Hydration and Serialization Problem
The main argument of RSC defenders: "We eliminated hydration!" That's true, but only partially.
Yes, RSC components don't get hydrated. They arrive as ready-made HTML. But as soon as you need interactivity for even a single "Buy" button, you add the 'use client' directive. And that's when the magic of the Network Boundary begins.
Instead of simply serving HTML, the server now must:
- Render the Server Components.
- Serialize props for Client Components (and heaven forbid you pass a function or class — serialization error!).
- Send HTML + JSON with hydration data.
- The browser must download React, download client component code, and execute the code again to "bring the HTML to life."
How we broke an entire wardrobe for a single hinge
It's as if you bought a wardrobe. The server (Server Component) assembles it at the warehouse and delivers it ready-made. You see a beautiful wardrobe. Hooray!
But then a crew of movers walks in (Client Component/Hydration). They say: "We need to make sure the doors open." They disassemble your assembled wardrobe back into planks right in your hallway. And then, consulting the instructions (JSON data), they reassemble it from scratch before your eyes, wasting your time and CPU resources.

We're literally making the computer do the work twice. First on the server, then on the client. Efficient? No. Trendy? Yes.
The Cost of Complexity
All this complexity has a concrete price.
Scenario: a simple e-commerce store.
PHP/Go/Python stack (Classic):
- VPS: 500 rubles/month.
- Database: on the same VPS (free).
- Deploy:
git pullor Docker Compose. - Total: 500 rubles. Predictable. Sanctions-proof.
Next.js stack (cloud):
- Vercel Pro (to avoid hitting limits): $20/month (2,000 rubles).
- Foreign card payment: hassle with intermediaries (+20%).
- Cold start latency: your serverless functions "sleep." The first user waits several seconds.
- Total: from 2,500 rubles + payment headaches + account suspension risk.
Next.js stack (Docker):
- VPS: 500 rubles/month (same as PHP).
- Complexity: you need to write a
Dockerfile(multi-stage build), configure Nginx for static files, Redis for caching, and figure out whysharpwon't build on Alpine Linux. - Total: 500 rubles + your free weekends spent on DevOps.
We're not paying for load. We're paying for architectural complexity and vendor lock-in.
The "Edge Runtime" Trap
There's another nuance the marketing brochures stay silent about. Vercel actively promotes Edge Middleware and Edge Functions. "It's faster! It runs on the CDN!" they say.
But what is this "edge" runtime? It's castrated JS. Forget about fs, forget about the familiar Node API. You've been locked in a sandbox and told it's innovation. Code written for Edge won't run in a standard Node.js container on your cheap VPS.
You're writing code that can work only in Vercel's infrastructure (or Cloudflare Workers). You're handcuffing yourself to vendor lock-in with your own hands. Want to move to your own hardware when the Vercel bill exceeds $1,000? Rewrite half the backend. You just need to explain that to the business.
The Cult of Complexity and Resume-Driven Development
Why do we do this? Because nobody wants to write on their resume: "Maintain legacy jQuery; the business is happy." Everyone wants: "Microfrontend architect on Next.js App Router, migrated project to Edge Runtime."
The industry rewards complexity. If you keep it simple — you're a junior. If you make it complex — you're a senior. This is the JavaScript industrial complex at work. We create problems to heroically solve them and demand a raise. And the business? The business just pays for "modern technologies" without understanding it's buying hot air.
The Framework as a Corset
But let's be fair. RSC and heavyweight frameworks like Next.js have one indisputable killer feature — team scalability.
When you have 50, 100, or 500 frontend developers, the business's main problem isn't page load speed or server costs. The main problem is the Brownian motion of developers. Everyone writes code in their own style, everyone invents their own state management bicycle and their own architectural pattern for data fetching.
At that point, Next.js with its strict file-based routing and RSC becomes an architectural corset. It forces everyone onto the same rails. Step left, step right — compilation error. In bloody enterprise, you need all 500 people's code to look equally ugly, but uniformly so. You trade application performance for assembly-line production where any developer can be replaced within a week.
But when you, as an indie developer or tech lead of a 3-person startup, voluntarily drag this enterprise tool into your project (yes, your personal blog)... you're putting on a straitjacket for no reason.
What Should You Do?
I'm not calling for everyone to return to 2010 (though index.html is still beautiful). I'm calling for engineering honesty.
- Calculate TCO (Total Cost of Ownership). In Russia right now, it's simpler and cheaper to spin up a VPS than to struggle with cloud payments. Don't drag Next.js into places where simple Go/Python or PHP will suffice.
- Use native browser capabilities. The View Transitions API already makes transitions smooth, and new HTML/CSS features let you build complex interfaces without gigabytes of JS.
- Don't fall for marketing. Vercel sells hosting. It's in their interest for your code to be complex and tied to their servers.
Sometimes the best framework is no framework at all.
Checklist: Do You Need Next.js?
I'm not against progress. Next.js and RSC are powerful tools. But using them for a blog is like hammering nails with a microscope. Here's a simple decision algorithm:
You NEED Next.js / RSC if:
- You're building Facebook-scale / Airbnb (hundreds of routes, complex state machine).
- You critically need Optimistic UI (the interface responds faster than the server answers).
- You have a team of 50+ frontend developers and need the framework's strict rails to prevent spaghetti code.
You DON'T need Next.js (use Python, Go, PHP) if:
- You're making a blog or content site. (HTML caches better than JSON.)
- You're building a B2B admin panel. (No SEO needed there — you need reliable application state management, and a good old SPA on Vite + React will be easier to debug.)
- You're a startup with a budget of 0. (A VPS for 300 rubles will handle 10k users on PHP/Go. Vercel will send you a bill at the first DDoS attack.)
Conclusion
P.S. This article is an adapted excerpt from my book "Generation JSON." In it, I translate our everyday engineering pains into the language of money and show why "free" abstractions often cost businesses the most.