Antlers Next.js — Phase 2 Performance Baseline
Date: 2026-05-27
Site measured: https://staging-nextjs.raxx.app/
Issue: #2881
Method: Lighthouse CLI 13.3.0 (--only-categories=performance, headless Chrome, simulated 4G throttling), curl TTFB (3 trials each, median reported)
CRA comparison source: local build at frontend/trademaster_ui/build/ (raxx.app is CF Access-gated; Lighthouse redirected to Access login page and cannot measure app)
1. Bundle Size
1a. Next.js scaffold (live staging — per-chunk)
| Asset | Raw (B) | Gzip (B) | Gzip (KiB) | Notes |
|---|---|---|---|---|
fd9d1056-*.js |
172,834 | 53,802 | 52.5 | Largest vendor chunk (React runtime + router) |
polyfills-*.js |
112,594 | 39,503 | 38.6 | Next.js polyfills |
30-be3f1d*.js |
124,584 | 31,901 | 31.2 | Framework chunk |
webpack-*.js |
3,444 | 1,660 | 1.6 | Webpack runtime |
main-app-*.js |
631 | 266 | 0.3 | App entry (scaffold) |
| JS total | 414,087 | 127,132 | 124.2 | |
37d05d8*.css |
1,324 | 592 | 0.6 | Scaffold CSS only |
| HTML (SSR) | 7,752 | 3,160 | 3.1 | Inline RSC payload |
| Page subtotal | 423,163 | 130,884 | 127.8 | Excludes font |
| Inter WOFF2 (googleapis) | — | 48,464 | 47.3 | External font, one file |
| Total (incl. font) | — | 179,348 | 175.1 | Matches LH "155 KiB" estimate (LH uses different accounting) |
1b. CRA build (local frontend/trademaster_ui/build/ — baseline)
| Asset | Raw (B) | Gzip (B) | Gzip (KiB) |
|---|---|---|---|
main.dec84704.js |
1,328,582 | 389,744 | 380.6 |
206.28995197.chunk.js |
4,444 | 1,750 | 1.7 |
| JS total | 1,333,026 | 391,494 | 382.3 |
main.f362b66d.css |
292,238 | 42,290 | 41.3 |
index.html |
677 | 417 | 0.4 |
| Total | 1,625,941 | 434,201 | 424.0 |
1c. Delta (scaffold vs full CRA app)
| Dimension | Next.js scaffold | CRA full app | Delta |
|---|---|---|---|
| JS (gzip, KiB) | 124.2 | 382.3 | −258.1 KiB (−67.5%) |
| CSS (gzip, KiB) | 0.6 | 41.3 | −40.7 KiB (scaffold CSS only) |
| HTML (gzip, KiB) | 3.1 | 0.4 | +2.7 KiB (SSR inline RSC payload) |
Interpretation: The scaffold delta is not meaningful for post-port comparison — Next.js CSS is a stub (full Bootstrap/CE styles not yet ported). JS runtime savings are real and structural: Next.js per-route code-split versus CRA single-bundle. The JS delta will compress post-port as app code is added back but routing efficiency is retained.
2. Core Web Vitals
Lighthouse 13.3.0, simulated 4G throttling, single run per route (scaffold has near-zero variance — same placeholder content on all routes except /signup). /setup redirects 307 → /login?next=%2Fsetup; metrics reflect the login page.
| Route | Score | FCP | LCP | TTI | TBT | CLS | Speed Index |
|---|---|---|---|---|---|---|---|
/ |
91 | 2.7 s | 2.8 s | 2.8 s | 0 ms | 0 | 2.7 s |
/login |
93 | 2.6 s | 2.6 s | 2.6 s | 0 ms | 0 | 2.8 s |
/signup |
96 | 1.6 s | 2.6 s | 2.6 s | 0 ms | 0 | 1.6 s |
/setup (→ /login) |
92 | 2.7 s | 2.7 s | 2.7 s | 0 ms | 0 | 2.8 s |
Issue-level acceptance criteria (from #2881):
- LCP < 2.5 s: MISS on all four routes (range 2.6–2.8 s). Delta: +100 to +300 ms over threshold.
- FCP < 1.8 s: MISS on /, /login, /setup (2.6–2.7 s). PASS on /signup (1.6 s).
Root cause of FCP/LCP miss: Inter font loaded from fonts.googleapis.com with no font-display: optional or local fallback. Font discovery starts at HTML parse → CSS fetch → woff2 fetch, adding ~1.1–1.2 s to render. The font woff2 is 47.3 KiB. Fix: self-host Inter with next/font (zero render-blocking) — this is a Phase 3 port item, not a scaffold regression.
TBT = 0, CLS = 0: confirms correct — scaffold has no long tasks and no layout shift.
3. TTFB
3-trial measurements via curl, median selected.
| Route | Next.js staging (median TTFB) | CRA raxx.app (median TTFB) | Delta |
|---|---|---|---|
/ |
116 ms | 56 ms | +60 ms |
/login |
140 ms | 48 ms | +92 ms |
/signup |
183 ms | 52 ms | +131 ms |
/setup |
104 ms | — | — |
Trial data:
Next.js staging:
| Route | Trial 1 | Trial 2 | Trial 3 | Median |
|---|---|---|---|---|
/ |
111 ms | 116 ms | 146 ms | 116 ms |
/login |
438 ms | 140 ms | 118 ms | 140 ms |
/signup |
184 ms | 117 ms | 295 ms | 184 ms |
/setup |
116 ms | 91 ms | 86 ms | 104 ms |
CRA raxx.app (CF Pages static):
| Route | Trial 1 | Trial 2 | Trial 3 | Median |
|---|---|---|---|---|
/ |
57 ms | 52 ms | 152 ms | 57 ms |
/login |
49 ms | 38 ms | 48 ms | 49 ms |
/signup |
50 ms | 58 ms | 48 ms | 50 ms |
Interpretation: Next.js runs on CF Workers edge runtime (x-edge-runtime: 1 confirmed in response headers) with SSR. CRA is a static asset served from CF Pages CDN edge cache. The TTFB delta (60–131 ms) is expected: SSR invokes a Worker function per request whereas static HTML is edge-cached. This is an acceptable trade-off when SSR enables server-side auth checks (middleware.ts route guard). One /login trial spiked to 438 ms — likely a cold start; median is unaffected.
Non-US vantage: not available in this run (single vantage from LAX colo per cf-ray: a029…-LAX). Recommend adding a multi-region curl probe in Phase 3 CI (e.g. via curl-to-url GH Actions matrix with runs-on: ubuntu-latest on different runner regions, or Cloudflare Observatory API if accessible).
4. Network Waterfall (Home Page)
11 total requests on first load.
| # | Type | Asset | Transfer |
|---|---|---|---|
| 1 | Document | staging-nextjs.raxx.app/ (SSR HTML) |
3,160 B |
| 2 | Stylesheet | 37d05d892a8d6825.css |
1,087 B |
| 3 | Script | webpack-4471baf625a7707f.js |
2,156 B |
| 4 | Script | fd9d1056-*.js (React runtime) |
54,664 B |
| 5 | Script | 30-be3f1d*.js (framework) |
32,838 B |
| 6 | Script | main-app-bd268aaccf88b235.js |
735 B |
| 7 | Stylesheet | Google Fonts CSS | 1,233 B |
| 8 | Script | CF RUM beacon | 11,672 B |
| 9 | Font | Inter woff2 | 48,464 B |
| 10 | XHR | CF RUM ping | 458 B |
| 11 | Other | favicon.ico (404) | 2,520 B |
Critical path: HTML → CSS → JS chunks (async) → Google Fonts CSS → woff2. The font chain (items 7→9) is the render blocker driving FCP to ~2.7 s.
Largest single asset: fd9d1056-*.js at 54,664 B transferred (React runtime + router). Post-port this chunk will not grow significantly — it is framework code, not app code.
favicon.ico 404: minor — CF Pages default behavior for Workers route; fix in Phase 3 by placing favicon.ico in the public/ directory.
5. Lighthouse JSON Artifacts
Stored in docs/qa/lighthouse/ for future diff:
antlers-next-staging-home-2026-05-27.jsonantlers-next-staging-login-2026-05-27.jsonantlers-next-staging-signup-2026-05-27.jsonantlers-next-staging-setup-2026-05-27.json
6. Baseline Locked
Deploy SHA: 46c57e14 — ci(antlers-next): Wave B Phase 1 — promote CI gates to required checks (#2937)
Build ID (Next.js): Y-F9GQODO3-2tEmeEfr72 (from RSC payload in HTML)
Repo HEAD at measurement: 773b3b50
Lighthouse version: 13.3.0
Measurement date: 2026-05-27 (UTC)
Vantage: US-West / LAX (cf-ray: a029…-LAX)
7. Recommended Phase 3 Regression Thresholds
These become CI blockers at Phase 3 cutover review (not informational-only):
| Metric | Baseline | Block if | Rationale |
|---|---|---|---|
| LCP | 2.8 s (scaffold) | > 3.5 s on any ported route | +700 ms buffer; scaffold penalized by external font; post-next/font target is <2.5 s |
| FCP | 2.7 s (scaffold) | > 3.0 s on any ported route | +300 ms buffer; font self-hosting fix expected in Phase 3 |
| First-load JS | 124 KiB gz | > 200 KiB gz (any single route chunk) | Next.js per-route splitting; a single chunk crossing 200 KiB means a split opportunity was missed |
| Total byte weight | 155 KiB (scaffold) | > 400 KiB (any route, all assets) | Headroom for full CE skin + Bootstrap; crossing 400 KiB requires explicit justification |
| TTFB | 116–184 ms (median) | > 500 ms (median of 3 trials) | Cold-start outlier at 438 ms already observed; 500 ms median means systematic regression |
8. Open Questions
- FCP/LCP target compliance post-font fix: Migrating to
next/font/googlewithdisplay: swapordisplay: optionalis expected to reduce FCP to <1.8 s and LCP to <2.5 s (AC targets from #2881). This should be validated in Phase 3 before setting blockers. - Multi-region TTFB: The LAX colo result does not prove global edge distribution. Add a US-East probe (GH Actions
ubuntu-latestrunner is typically US-East) to the Phase 3 CI workflow. - CF Workers cold start: One
/logintrial hit 438 ms. If cold starts persist post-port with real app code, evaluate@cloudflare/next-on-pagescaching strategies or Workers unbound plan for warm instances. - CRA comparison completeness: CRA TTFB/Lighthouse measurements are unavailable from CF Access-gated
raxx.app. The local build provides bundle sizes but no live CWV comparison. Phase 3 should measure CRA live before cutover (via a service token bypass) to get a true before/after. - favicon.ico 404: Low priority but creates a wasted 2.5 KiB request + 404 error on every page load. Fix before Phase 3 cutover.