How to measure performance
Five independent ways to measure the SSR, Client, and RSC variants in this demo. Pick whichever matches your audience: Lighthouse for the standard scorecard, the built-in pnpm vitals script for headless A/B comparison, or PageSpeed Insights for deployed-URL field data.
Sample results — blog post
Lighthouse 12.8.2 · desktop preset · 50 ms delay · 2026-05-09
Captured against the deployed site with npx lighthouse <url>?delay=50 --preset=desktop --only-categories=performance. Click any score to drill into the full Lighthouse HTML report.
Desktop reports use 50 ms artificial DB delay to emulate real-world load
This demo app is small and fast — under normal conditions all three rendering strategies score similarly on desktop.
PageSpeed Insights does not throttle CPU or network on desktop, so it cannot surface the performance differences
that matter in production. Adding ?delay=50 to every
page injects a 50 ms sleep after each database query, simulating the heavier queries and higher latency of a real-world application.
This makes the RSC streaming advantage clearly visible in Lighthouse scores. The 50 ms delay emulates typical database latency
and API response times seen in production applications under load.
Five ways to measure
In rough order of effort vs depth. The first two are interactive (one-off audits). The third is built into this repo and the most repeatable. Four and five hit deployed URLs.
Lighthouse in Chrome DevTools
Best for a single-page audit with the full diagnostics report (Performance + Best Practices + Accessibility + SEO).
- Open the page in Chrome (incognito recommended).
- Open DevTools — Cmd+Opt+I (mac) / F12 (Win).
- Switch to the Lighthouse panel.
- Pick Mobile, check Performance, leave Simulated throttling on, click Analyze page load.
Run each variant from a fresh incognito window so cache state matches.
Lighthouse CLI
Use in CI or for repeatable per-commit benchmarks.
npx -y lighthouse http://localhost:3000/blog/rsc \
--preset=desktop \
--only-categories=performance \
--output=html \
--output-path=./tmp/lh-blog-rsc.html
# Repeat for /blog/ssr and /blog/client.
Add --throttling-method=devtools + --screenEmulation.mobile for the mobile profile.
Built-in pnpm vitals
Recommended
Headless Chrome (Puppeteer) script that captures FCP / LCP / TTFB / TBT / CLS / hydration / streaming / JS transfer + decoded for every variant and prints a side-by-side table. Best option for stable, reproducible benchmarks — eliminates CDN and network variance that affects PageSpeed.
Setup — clone & build production
# Clone the repo
git clone https://github.com/shakacode/react-on-rails-demo-marketplace-rsc.git
cd react-on-rails-demo-marketplace-rsc
# Install dependencies
bundle install && pnpm install
# Build production assets
NODE_ENV=production bin/shakapacker --mode production
# Start node renderer (background)
NODE_ENV=production node node-renderer.js &
# Start Rails in production mode
RAILS_ENV=production RAILS_SERVE_STATIC_FILES=true \
SECRET_KEY_BASE=dummy_secret_key_base_for_testing_1234567890abcdef \
bundle exec rails server -p 3000
RAILS_SERVE_STATIC_FILES=true required for local prod — otherwise Rails won't serve CSS/JS.
Desktop (no throttle)
# Quick run (3 iterations, 1 warmup)
pnpm vitals:quick
# Full run (7 iterations, 2 warmup)
pnpm vitals
# Specific pages only
pnpm vitals -- --pages blog-ssr,blog-rsc
Desktop mode = no CPU/network throttle. Fast but doesn't reveal streaming advantage.
Mobile (throttled) — matches PSI
# 4x CPU slowdown + Slow 3G network
pnpm vitals -- --throttle
# Quick + throttled
pnpm vitals:quick -- --throttle
# Throttled specific pages
pnpm vitals -- --throttle --pages blog-ssr,blog-rsc
--throttle = 4x CPU slowdown + Slow 3G. Matches PageSpeed Insights mobile conditions.
Compare before/after
# Run baseline, save with label
pnpm vitals -- --throttle --label before
# Make changes, run again
pnpm vitals -- --throttle --label after
# Compare side-by-side
pnpm vitals:compare -- \
.vitals-results/*-before.json \
.vitals-results/*-after.json
All available page keys
blog-ssr, blog-client, blog-rsc
product-ssr, product-client, product-rsc
search-ssr, search-client, search-rsc
restaurant-ssr, restaurant-client, restaurant-rsc
dashboard-ssr, dashboard-client, dashboard-rsc
Full list in scripts/lib/constants.mjs
JSON output: .vitals-results/<timestamp>.json. Source: scripts/measure-vitals.mjs.
PageSpeed Insights
Lighthouse + Chrome UX Report (real-user field data) for the production deployment at rsc.reactonrails.com. Deep links by route are in the table further down the page.
PageSpeed results can vary significantly for demo sites
PSI scores depend on CDN cache state, server warmup, and Google infrastructure variance. For low-traffic demo sites like this one, we observed 18-32 point variance between runs. For stable, reproducible benchmarks, use pnpm vitals -- --throttle against a local production build instead. Local benchmarks with throttling match PSI conditions (4x CPU slowdown) but eliminate network/CDN variance.
Important: warm up each page before running PageSpeed
Visit the page URL in your browser first (or curl it) to prime server caches. Cold-start times can inflate metrics by several seconds. Desktop links below include ?delay=50 to simulate production-level DB load — PageSpeed does not throttle CPU or network on desktop, so without the delay all three variants score nearly identically.
WebPageTest
Best when you need a video filmstrip showing streaming differences side-by-side.
npm i -g webpagetest
webpagetest test https://rsc.reactonrails.com/blog/rsc \
--location Dulles:Chrome.3GSlow --runs 3
Or paste the URL directly at webpagetest.org.
All measurable routes
Open any local URL directly. Add ?delay=50 to simulate production DB load.
Warm up before measuring
Visit each page URL once before running PageSpeed Insights — the first request after a deploy or idle period hits a cold server and inflates all metrics.
Desktop PageSpeed links below include ?delay=50 because PageSpeed does not throttle CPU or network on desktop.
Without the delay, this small demo app is too fast for Lighthouse to detect meaningful differences between SSR, Client, and RSC.
| Page | Local | PageSpeed · desktop · delay=50 |
|---|---|---|
| Blog SSR | /blog/ssr | PageSpeed → |
| Blog Client | /blog/client | PageSpeed → |
| Blog RSC | /blog/rsc | PageSpeed → |
| Product SSR | /product/ssr | PageSpeed → |
| Product Client | /product/client | PageSpeed → |
| Product RSC | /product/rsc | PageSpeed → |
| Product PPR | /product/ppr | PageSpeed → |
| Product RSC Pull | /product/rsc-pull | PageSpeed → |
| Restaurant Detail SSR | /restaurant/1/ssr | PageSpeed → |
| Restaurant Detail Client | /restaurant/1/client | PageSpeed → |
| Restaurant Detail RSC | /restaurant/1/rsc | PageSpeed → |
| Product Search SSR | /product-search/ssr | PageSpeed → |
| Product Search Client | /product-search/client | PageSpeed → |
| Product Search RSC | /product-search/rsc | PageSpeed → |
Tips for credible numbers
Single-run localhost numbers will look great on every variant. The differences only become real under throttling, with cache cleared, in incognito.