DEV Community

sweet
sweet

Posted on

Lighthouse 95+ Optimization Playbook: SaaS Performance Guide

Achieving Lighthouse 95+ scores is not about chasing a number — it's about engineering a performant experience that directly impacts SaaS conversion rates. This playbook covers Core Web Vitals optimization, SSR with streaming, Critical CSS, bundle splitting, image optimization, and caching strategies. Every recommendation is actionable and production-tested. A 30-point checklist is included at the end.


Introduction: Why Lighthouse 95+ Matters for SaaS

In SaaS, every millisecond counts. Google's research has repeatedly shown that a 1-second delay in mobile page load reduces conversion rates by up to 20%. For a B2B SaaS product with a $100 monthly ARPU and 10,000 signups per month, that delay translates to over $2 million in annual revenue loss.

But the impact goes deeper:

  • SEO Rankings: Google uses Core Web Vitals as a ranking signal. A site scoring below 50 on Lighthouse is unlikely to rank competitively.
  • User Trust: Lighthouse scores correlate strongly with perceived reliability.
  • Ad Spend Efficiency: Lower Quality Scores on Google Ads mean higher cost-per-click.

Lighthouse 95+ is a compound growth lever that touches acquisition, activation, and retention simultaneously.


Understanding Core Web Vitals

Metric What It Measures Target
LCP (Largest Contentful Paint) Loading performance <= 2.5s
CLS (Cumulative Layout Shift) Visual stability <= 0.1
INP (Interaction to Next Paint) Interactivity <= 200ms

Performance Budgets: Set Targets from Day One

Define budgets for:

  • JavaScript bundle size: 150 KB (compressed) for critical route, 300 KB max
  • Time to Interactive: < 3s on 3G
  • LCP: < 2.0s
  • Total page weight: < 500 KB (compressed)

Enforce in CI:

// lighthouse-budget.js
module.exports = {
  ci: {
    collect: { numberOfRuns: 3, settings: { preset: 'desktop' } },
    assert: {
      assertions: {
        'categories:performance': ['error', { minScore: 0.95 }],
        'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
        'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
        'total-blocking-time': ['error', { maxNumericValue: 200 }],
      },
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

LCP Optimization

1. SSR with Streaming

TanStack Start supports streaming SSR out of the box. Ensure you are not disabling it:

const router = createRouter({
  routeTree,
  defaultPreload: 'intent',
  // Streaming is enabled by default in TanStack Start
});
Enter fullscreen mode Exit fullscreen mode

2. Critical CSS

Inline the CSS required for above-the-fold content. Defer the rest:

<head>
  <style>
    /* Critical CSS — inline above-the-fold styles */
    header, .hero, .cta-button { /* essential styles */ }
  </style>
  <link rel="preload" href="/styles/full.css" as="style"
        onload="this.onload=null;this.rel='stylesheet'" />
  <noscript><link rel="stylesheet" href="/styles/full.css" /></noscript>
</head>
Enter fullscreen mode Exit fullscreen mode

3. Font Loading

Use font-display: swap and preload your primary font:

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-var.woff2') format('woff2');
  font-display: swap;
  font-weight: 100 900;
}
Enter fullscreen mode Exit fullscreen mode

Preload it in the HTML head:

<link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin />
Enter fullscreen mode Exit fullscreen mode

4. Optimize the LCP Element

  • Preload it: <link rel="preload" as="image" href="https://webproxy.poorya-velaei-d67.workers.dev/https://dev.to/hero.webp" />
  • Use responsive images for different viewports
  • Avoid lazy loading the LCP element

CLS Optimization

1. Set Explicit Dimensions

<img
  src="/dashboard-screenshot.webp"
  width="1200"
  height="675"
  alt="Dashboard preview"
  loading="lazy"
/>
Enter fullscreen mode Exit fullscreen mode

2. Font Fallback Metrics

@font-face {
  font-family: 'Inter Fallback';
  src: local('Arial');
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}
Enter fullscreen mode Exit fullscreen mode

3. Reserve Space for Dynamic Content

.newsletter-signup-placeholder {
  min-height: 120px;
  /* Reserve space while async content loads */
}
Enter fullscreen mode Exit fullscreen mode

JavaScript Optimization

1. Route-Based Code Splitting

TanStack Router supports route-based code splitting natively:

// routes/dashboard.tsx
export const Route = createLazyRoute('/dashboard')({
  component: DashboardComponent,
});
Enter fullscreen mode Exit fullscreen mode

2. Tree Shaking

  • Use named imports: import { useQuery } from '@tanstack/react-query'
  • Mark side-effect-free packages: "sideEffects": false

3. Lazy Load Non-Critical Code

<script>
  window.addEventListener('load', () => {
    setTimeout(() => {
      const script = document.createElement('script');
      script.src = 'https://widget.example.com/loader.js';
      script.async = true;
      document.body.appendChild(script);
    }, 3000);
  });
</script>
Enter fullscreen mode Exit fullscreen mode

Image Optimization

1. Responsive Images with srcset

<img
  src="/hero-1200.webp"
  srcset="/hero-400.webp 400w, /hero-800.webp 800w, /hero-1200.webp 1200w"
  sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px"
  width="1200" height="675" alt="Product dashboard"
/>
Enter fullscreen mode Exit fullscreen mode

2. Modern Formats: WebP and AVIF

<picture>
  <source srcset="/hero.avif" type="image/avif" />
  <source srcset="/hero.webp" type="image/webp" />
  <img src="/hero.jpg" width="1200" height="675" alt="Hero" />
</picture>
Enter fullscreen mode Exit fullscreen mode

Caching Strategy

1. CDN Caching

Cache-Control: public, max-age=31536000, immutable  # Versioned assets
Cache-Control: public, max-age=3600, s-maxage=86400  # HTML pages
Enter fullscreen mode Exit fullscreen mode

2. TanStack Query Caching

const { data } = useQuery({
  queryKey: ['pricing-plans'],
  queryFn: fetchPricingPlans,
  staleTime: 5 * 60 * 1000,
  gcTime: 30 * 60 * 1000,
});
Enter fullscreen mode Exit fullscreen mode

30-Point Performance Checklist

Critical

  • [ ] LCP element is identified and preloaded
  • [ ] All images have explicit width and height
  • [ ] Critical CSS is inlined, full CSS is deferred
  • [ ] Custom fonts use font-display: swap
  • [ ] No render-blocking third-party scripts
  • [ ] LCP image uses WebP/AVIF with responsive srcset
  • [ ] Server response time (TTFB) < 800ms
  • [ ] Route-based code splitting is implemented
  • [ ] Unused JavaScript is removed or deferred
  • [ ] Hero image is not lazy-loaded

High Priority

  • [ ] All raster images converted to WebP or AVIF
  • [ ] Font fallback metrics are tuned
  • [ ] Third-party embeds have reserved space
  • [ ] Analytics scripts load after onLoad
  • [ ] Long tasks (>50ms) are identified and split
  • [ ] JavaScript bundles use Brotli compression
  • [ ] Static assets use immutable cache headers
  • [ ] CDN is configured for all asset types
  • [ ] TanStack Query staleTime is set appropriately
  • [ ] Service worker caches API responses

Medium Priority

  • [ ] All images use lazy loading (except LCP)
  • [ ] preconnect hints for critical origins
  • [ ] dns-prefetch for analytics domains
  • [ ] HTML is minified
  • [ ] CSS is minified, unused rules purged
  • [ ] No render-blocking JS above the fold
  • [ ] Preload key API routes
  • [ ] Use will-change sparingly
  • [ ] Minimize 301 redirects per page load
  • [ ] Run Lighthouse CI on every PR

Conclusion

A Lighthouse 95+ score is about engineering a fast, reliable, and delightful user experience that directly grows your SaaS business. The approach is systematic:

  1. Set budgets before you write code
  2. Measure continuously in lab and field
  3. Optimize the critical path: SSR streaming, Critical CSS, font loading, images
  4. Control JavaScript with route splitting and deferred loading
  5. Cache everything aggressively

Start with the checklist. Pick the critical items first. Run Lighthouse CI on every PR. Your users — and your revenue — will thank you.


Related Resources

Top comments (0)