Skip to main content
ADR-015accepted

Critical Rendering Path Optimization Strategy

Context

The portfolio's target audience — technical hiring managers and VPs of Engineering — often evaluate sites on mobile devices during commutes or between meetings, on variable network conditions. First Contentful Paint (FCP) and Largest Contentful Paint (LCP) directly determine whether a visitor waits or bounces. The default Next.js setup produces reasonable performance, but several render-blocking patterns exist by default: external font loading, synchronous script execution, unoptimized resource discovery, and third-party script payloads (Google Analytics). Each of these adds milliseconds to the critical path — the sequence of resources that must load before the user sees meaningful content. The cumulative effect of unoptimized defaults can add 500ms-1s to FCP on 3G connections. For a portfolio that competes with other candidates' sites in a hiring manager's browser tabs, every 100ms matters.

Decision

Implement a multi-layer critical rendering path optimization. Font loading: Geist fonts loaded via next/font/local with font-display: swap, eliminating external font CDN requests and ensuring text is visible immediately with system font fallback during load. Resource hints: preconnect to critical origins (statics.lucioduran.com, api.lucioduran.com, googletagmanager.com) in _document.js Head, with dns-prefetch fallbacks for browsers that don't support preconnect. Script loading: Google Analytics loaded with async attribute, and the gtag configuration executed inline to avoid a second network round-trip. No other third-party scripts are loaded. CSS delivery: styled-components' ServerStyleSheet extracts critical CSS during SSR and inlines it in the document head, eliminating FOUC and the need for external CSS requests. Image optimization: Next.js Image component with priority flag on above-the-fold images, automatic WebP/AVIF conversion, and lazy loading for below-the-fold content. HTTP: poweredByHeader disabled (removes X-Powered-By header, reducing response size by ~20 bytes per request), compress enabled for gzip/brotli.

Consequences

Positive: Lighthouse performance score consistently 95-100 across all pages. FCP under 1.0s on 4G, under 1.8s on 3G. LCP under 1.5s on 4G. Zero external CSS requests — all styles are inlined via ServerStyleSheet. The preconnect hints save ~100ms on the first API request by establishing TCP/TLS connections early. font-display: swap ensures text is visible within 50ms of page load (system font rendering) before Geist loads. The single third-party script (GA) loads asynchronously and does not block any rendering. Negative: ServerStyleSheet adds server-side rendering overhead (~20ms per page) — acceptable for SSG where rendering happens at build time, but would be a concern for SSR pages. The inline critical CSS increases HTML document size by 15-30KB per page (all styled-component styles are embedded). Preconnect hints are only effective for the first page load — subsequent navigations benefit from HTTP keep-alive instead. The optimization is tuned for the current page structure; significant layout changes would require re-evaluating the critical path.

Calibrated Uncertainty

Predictions at Decision Time

Expected Lighthouse scores above 90 after optimization. Predicted FCP under 1.5s on 4G. Assumed preconnect hints would save 50-150ms on initial API requests. Predicted the inline CSS approach would increase HTML size by 10-20KB. Expected Google Analytics to be the only performance-impacting third-party script.

Measured Outcomes

Lighthouse scores consistently hit 95-100, exceeding the >90 target. FCP measured at <1.0s on 4G, significantly better than the 1.5s prediction. Preconnect hints save approximately 100ms on the first API-dependent request — within the predicted range. Inline CSS increases HTML size by 15-30KB, slightly above the 10-20KB prediction due to the number of styled components growing from 80 to 120+ as new sections were added. GA remains the only third-party script. The unexpected outcome: the font-display: swap strategy produces a barely noticeable FOUT (Flash of Unstyled Text) on the very first visit — Geist loads within ~100ms, so the system font flash is brief but technically present.

Unknowns at Decision Time

Did not know at decision time how many styled components would exist at scale — the inline CSS size grows linearly with component count. At 120+ components, the 15-30KB inline CSS is approaching the point where extraction to external CSS with caching would be more efficient for repeat visitors. Also unknown: whether Vercel's edge network would implement early hints (103 responses) that could further optimize resource discovery. They have not as of February 2026. Unknown: the cumulative impact of future third-party scripts (error monitoring, heatmaps, A/B testing) that might be added — the current strategy assumes GA is the only third-party dependency.

Reversibility Classification

Two-Way Door

Each optimization is independently reversible. Preconnect hints: remove link tags from _document.js. Font strategy: switch next/font/local config. Script loading: change async to defer or remove. ServerStyleSheet: remove from _document.js (accepting FOUC). Each change is localized to one file and testable independently. Estimated effort to reverse any single optimization: 15-30 minutes.

Strongest Counter-Argument

The optimization effort targets marginal gains that are invisible to the user. The difference between 0.9s FCP and 1.4s FCP is not consciously perceptible — both register as 'fast.' A simpler approach: use Next.js defaults, add the Google Font link, and accept the ~1.5s FCP. The engineering time spent on preconnect hints, font-display strategies, and ServerStyleSheet configuration could be spent on content. Most hiring managers evaluate portfolio content, not Lighthouse scores. The counter-counter: performance optimization is itself a signal of engineering quality. A portfolio that scores 100 on Lighthouse communicates attention to detail — a meta-signal that the Lighthouse score itself is less important than the discipline it represents.

Technical Context

Stack
next/font/localServerStyleSheetpreconnectdns-prefetchasync scriptsNext.js Image
Lighthouse Performance
95-100
Fcp On4g
<1.0s
Fcp On3g
<1.8s
Lcp On4g
<1.5s
External Css Requests
0
Third Party Scripts
1
Constraints
  • No external font CDN
  • GA is the only third-party script
  • ServerStyleSheet required for styled-components SSR

Related Decisions