Skip to main content
Ganesh Joshi
Back to Blogs

Lighthouse CI: keep performance in check in CI

February 15, 20266 min read
Tips
Lighthouse or performance report on screen

Lighthouse scores drift as you add features and dependencies. A site that scored 95 on performance six months ago might drop to 75 after adding analytics, a chat widget, and a few unoptimized images. Running Lighthouse in CI on every pull request catches these regressions before they reach production.

What is Lighthouse CI?

Lighthouse CI is the official way to run Lighthouse audits in a pipeline. It handles browser automation, runs audits against one or more URLs, aggregates results from multiple runs, and asserts on scores or metrics. If a score drops below your threshold, the build fails or emits a warning.

Feature Description
Multiple runs Runs audits 3-5 times and takes the median to reduce noise
Assertions Fail builds if performance < 80 or LCP > 2.5s
Report storage Upload reports to LHCI server or temporary storage
CI integration Works with GitHub Actions, GitLab CI, CircleCI, Jenkins
Budget support Set budgets for metrics, resource sizes, or request counts

Lighthouse CI is not a replacement for manual audits or real user monitoring. It is a guardrail that catches obvious regressions in a controlled environment before code ships.

Installation and basic setup

Install Lighthouse CI as a dev dependency and create a configuration file.

npm install -D @lhci/cli

Create lighthouserc.js at the project root:

module.exports = {
  ci: {
    collect: {
      url: ['http://localhost:3000/', 'http://localhost:3000/about'],
      numberOfRuns: 3,
      startServerCommand: 'npm run start',
    },
    assert: {
      preset: 'lighthouse:recommended',
      assertions: {
        'categories:performance': ['error', { minScore: 0.8 }],
        'categories:accessibility': ['error', { minScore: 0.9 }],
        'largest-contentful-paint': ['warn', { maxNumericValue: 2500 }],
        'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
      },
    },
    upload: {
      target: 'temporary-public-storage',
    },
  },
};

Run with:

npx lhci autorun

The autorun command starts your server, runs Lighthouse against each URL the specified number of times, checks assertions, and uploads reports.

Choosing URLs to test

Test the pages that matter most for user experience and business goals:

Page type Why test it
Homepage First impression, often the LCP candidate
Key landing pages Marketing pages where users arrive from search
App shell or dashboard Critical for logged-in users
Heavy pages Pages with lots of images, scripts, or third-party embeds

Avoid testing every page. Focus on 3-5 representative URLs. Testing more pages increases CI time without proportional benefit. Add pages only when you have specific regressions to catch.

Running in GitHub Actions

Create .github/workflows/lighthouse.yml:

name: Lighthouse CI
on: [pull_request]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npm run build
      - name: Run Lighthouse CI
        run: npx lhci autorun
        env:
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}

For preview deployments (Vercel, Netlify), replace the localhost URLs with the preview URL. Vercel exposes this as VERCEL_URL in the environment. You can pass it to Lighthouse CI:

collect: {
  url: [
    `https://${process.env.VERCEL_URL}/`,
    `https://${process.env.VERCEL_URL}/about`,
  ],
  numberOfRuns: 3,
}

Setting effective thresholds

Start with thresholds you can meet today. The goal is to prevent regressions, not to block all PRs.

Metric Good starting threshold Stretch goal
Performance score 80 90
Accessibility score 90 100
LCP 2.5s 1.5s
CLS 0.1 0.05
TBT 300ms 150ms

Tighten thresholds over time. When your site consistently scores 85 on performance, raise the threshold to 85 so any regression triggers a warning.

Reducing flaky results

Lighthouse runs in a simulated environment and results vary. Network conditions, CPU throttling, and server response times all affect scores. To reduce flakiness:

  1. Run multiple audits: Use numberOfRuns: 3 or 5 and take the median.
  2. Use consistent environments: Test against preview deployments, not local dev servers with hot reloading.
  3. Avoid shared CI runners: If possible, use dedicated runners or machines with consistent specs.
  4. Disable animations: Long animations can affect CLS and LCP measurements.

If a test fails intermittently, check the report to see which metric varied. Metrics like TBT are more sensitive to CPU load than LCP.

Storing and comparing reports

Lighthouse CI can upload reports to temporary public storage (expires after a few days), an LHCI server you host, or Vercel Remote Cache.

To host your own LHCI server:

npm install -g @lhci/server
lhci server --storage.storageMethod=sql --storage.sqlDatabasePath=./lhci.db

In your config:

upload: {
  target: 'lhci',
  serverBaseUrl: 'https://your-lhci-server.com',
  token: process.env.LHCI_TOKEN,
}

The LHCI server provides a dashboard where you can compare scores across branches, view trends over time, and drill into individual reports.

Budget files for granular control

Beyond category scores, you can set budgets for specific resources:

assert: {
  budgetsPath: './budgets.json',
}

In budgets.json:

[
  {
    "path": "/*",
    "resourceSizes": [
      { "resourceType": "script", "budget": 200 },
      { "resourceType": "image", "budget": 500 }
    ],
    "resourceCounts": [
      { "resourceType": "third-party", "budget": 5 }
    ]
  }
]

This fails the build if JavaScript exceeds 200KB or if you load more than 5 third-party resources. Budgets are useful for catching dependency bloat.

Integrating with PR comments

Install the Lighthouse CI GitHub App to post score summaries as PR comments. The app compares the PR branch to the base branch and shows score changes.

  1. Install the app from github.com/apps/lighthouse-ci.
  2. Add LHCI_GITHUB_APP_TOKEN to your repository secrets.
  3. The app posts comments automatically when Lighthouse CI runs.

PR comments make performance visible to the whole team. A PR that drops performance by 10 points gets immediate feedback.

Common pitfalls

Pitfall Solution
Testing against dev server Build and serve production bundle
No numberOfRuns Always run 3-5 times for stability
Thresholds too strict Start lenient, tighten over time
Ignoring accessibility Include a11y assertions, not just performance
No report storage Use LHCI server or temporary storage for debugging

When Lighthouse CI is not enough

Lighthouse CI tests in a simulated environment with throttled network and CPU. Real users have different devices and connections. Complement Lighthouse CI with:

  • Real User Monitoring (RUM): Measure Core Web Vitals from actual visitors.
  • A/B testing: Compare performance impact of features.
  • Manual audits: Periodically run full Lighthouse audits and review opportunities.

Lighthouse CI catches obvious regressions. RUM tells you how real users experience your site.

Summary

Lighthouse CI integrates performance and accessibility checks into your CI pipeline. Set up a config file, choose thresholds, run audits on PRs, and store reports for comparison. Start with lenient thresholds and tighten them as your site improves. Combine CI checks with real user monitoring for a complete picture of site performance.

Frequently Asked Questions

Lighthouse CI is a tool that runs Lighthouse audits in your CI/CD pipeline. It tests pages for performance, accessibility, SEO, and best practices, then fails builds or warns if scores drop below your thresholds.

Install with npm install -D @lhci/cli, create a lighthouserc.js config file, and run npx lhci autorun. The config specifies URLs to test, number of runs, and assertion thresholds.

Start with minimum category scores like performance >= 80 and accessibility >= 90. Add metric budgets for LCP under 2.5s and CLS under 0.1. Tighten thresholds as your site improves.

Run multiple audits per URL (3-5 runs) and use median aggregation. Test against consistent environments like preview deployments. Avoid testing during high server load or on shared CI runners.

Yes. Use LHCI server for self-hosted storage or Vercel Remote Cache for cloud storage. Reports are viewable in a dashboard where you can compare scores over time and across branches.

Related Posts