Skip to content
Justin O'Halloran

Work / justinohalloran.com

Web performance, measured on this site

Static by default, no client components, system fonts, and Lighthouse scores published from real runs, spread included, rather than claimed.

Role
Everything
When
2026
Stack
Next.jsReact Server ComponentsTailwind CSSStorybookVercelLighthouse
Lighthouse performance
98
Measured
Lighthouse accessibility
100
Measured
Lighthouse best practices
100
Measured
Lighthouse SEO
100
Measured
Largest Contentful Paint
1.6 s
Measured
Total Blocking Time
180 ms
Measured
Cumulative Layout Shift
0
Measured
Page weight
175 KiB
Measured

Lab data: median of 3 mobile runs (performance 87, 98, 99); desktop preset scored 100, Lighthouse 12 default mobile (simulated slow 4G, 4x CPU slowdown), against the production deployment's home page on 2026-11-04. Lab scores swing from run to run, which is why the spread is published with the median.

The approach

  • Every page is statically generated at build time. There is no client-side data fetching and none of my components run on the client; React Server Components render the pages. The JavaScript that does ship (about 145 KB compressed) is the Next.js and React runtime plus Vercel Speed Insights, and it is the main cost left in the mobile score.
  • System font stacks, so no web-font request blocks first paint and nothing shifts when a font swaps in.
  • Design tokens compile to CSS custom properties at build time, so theming (including dark mode) costs no JavaScript.
  • Lighthouse runs against production are recorded above with their date and spread. Field data from real visitors comes from Speed Insights.

Earlier performance work

At JumpStartCSR I redesigned the company website on a custom Webpack 4 build and cut its file and image payloads by 60%. At Arc'teryx the content platform sat behind Fastly, and part of my job was the gateway and caching behaviour, and explaining it to the analysts and product managers who needed to know why a change was or was not live yet.