Lighthouse CI Configuration Reference

Complete guide to lighthouserc.js configuration options. Covers collect, assert, upload, and server settings for @lhci/cli.
Harlan WiltonHarlan Wilton Published

Lighthouse CI uses configuration files to define how audits are collected, assertions are evaluated, and results are uploaded.

Configuration File Formats

Lighthouse CI supports multiple configuration file formats, checked in priority order:

  1. .lighthouserc.js - JavaScript module (supports dynamic config)
  2. lighthouserc.js
  3. .lighthouserc.cjs - CommonJS explicit
  4. lighthouserc.cjs
  5. .lighthouserc.json - JSON format
  6. lighthouserc.json
  7. .lighthouserc.yml - YAML format
  8. lighthouserc.yml
  9. .lighthouserc.yaml
  10. lighthouserc.yaml

JavaScript Config

// lighthouserc.js
module.exports = {
  ci: {
    collect: {
      url: ['https://example.com/', 'https://example.com/about'],
      numberOfRuns: 3,
    },
    assert: {
      preset: 'lighthouse:recommended',
    },
    upload: {
      target: 'temporary-public-storage',
    },
  },
}

JSON Config

{
  "ci": {
    "collect": {
      "url": ["https://example.com/"],
      "numberOfRuns": 5
    },
    "assert": {
      "preset": "lighthouse:recommended"
    }
  }
}

Using CLI Flag

Override the default config file location:

lhci autorun --config=custom-config.js

Environment Variables

All configuration options can be set via environment variables using the LHCI_ prefix and double underscores for nesting:

# Equivalent to ci.collect.numberOfRuns
LHCI_COLLECT__NUMBER_OF_RUNS=5

# Equivalent to ci.upload.serverBaseUrl
LHCI_UPLOAD__SERVER_BASE_URL=https://lhci.example.com

# Equivalent to ci.upload.token
LHCI_UPLOAD__TOKEN=your-secret-token

Environment variables override config file values.

Collect Options

The collect configuration controls how Lighthouse audits are run.

Basic Collection

module.exports = {
  ci: {
    collect: {
      // URLs to audit (required)
      url: [
        'https://example.com/',
        'https://example.com/products',
        'https://example.com/about',
      ],

      // Number of times to audit each URL (default: 3)
      // 5 runs = 2x more stable than 1 run (Google research)
      // 3 runs = 37% variance reduction (DebugBear analysis)
      numberOfRuns: 5,

      // Lighthouse settings object
      settings: {
        preset: 'desktop',
        onlyCategories: ['performance', 'accessibility'],
      },
    },
  },
}

Static Site Collection

For auditing static builds before deployment:

module.exports = {
  ci: {
    collect: {
      // Path to built static files
      staticDistDir: './dist',

      // URLs to audit (relative to staticDistDir)
      url: [
        'http://localhost/index.html',
        'http://localhost/about/index.html',
      ],

      numberOfRuns: 3,
    },
  },
}

Server Command

Start a local server before collection:

module.exports = {
  ci: {
    collect: {
      startServerCommand: 'npm run serve',
      startServerReadyPattern: 'Server listening on',
      startServerReadyTimeout: 10000, // ms

      url: ['http://localhost:8080/'],
      numberOfRuns: 3,
    },
  },
}

The server process is automatically killed after collection completes.

Chrome Options

module.exports = {
  ci: {
    collect: {
      // Path to Chrome executable
      chromePath: '/usr/bin/google-chrome',

      // Chrome launch flags
      chromeFlags: '--no-sandbox --disable-gpu',

      // Puppeteer script for authentication/setup
      puppeteerScript: './scripts/puppeteer-script.js',

      // Puppeteer launch options
      puppeteerLaunchOptions: {
        headless: true,
      },
    },
  },
}

Puppeteer Script

For authenticated pages or complex setup:

// scripts/puppeteer-script.js
module.exports = async (browser, context) => {
  const page = await browser.newPage()
  await page.goto('https://example.com/login')
  await page.type('#username', 'user')
  await page.type('#password', 'pass')
  await page.click('#submit')
  await page.waitForNavigation()
}

Advanced Settings

module.exports = {
  ci: {
    collect: {
      // Disable headless mode for debugging
      headful: false,

      // Preserve previous collection data instead of replacing
      additive: false,

      // Maximum wait time for page load
      maxWaitForLoad: 45000, // ms

      // Lighthouse settings override
      // Note: simulated throttling (default) provides lowest variance
      // See: https://www.debugbear.com/blog/cpu-throttling-in-chrome-devtools-and-lighthouse
      settings: {
        throttling: {
          rttMs: 40,
          throughputKbps: 10240,
          cpuSlowdownMultiplier: 1,
        },
        screenEmulation: {
          mobile: false,
          width: 1350,
          height: 940,
          deviceScaleFactor: 1,
        },
      },
    },
  },
}

Assert Options

The assert configuration defines performance budgets and quality gates.

Presets

Three built-in presets provide baseline assertions:

module.exports = {
  ci: {
    assert: {
      // All Lighthouse audits must pass
      preset: 'lighthouse:all',

      // OR recommended audits only
      preset: 'lighthouse:recommended',

      // OR recommended excluding PWA audits
      preset: 'lighthouse:no-pwa',
    },
  },
}

Custom Assertions

Override preset or define custom assertions:

module.exports = {
  ci: {
    assert: {
      preset: 'lighthouse:recommended',
      assertions: {
        // Category scores (0-1)
        'categories:performance': ['error', { minScore: 0.9 }],
        'categories:accessibility': ['warn', { minScore: 0.95 }],
        'categories:seo': ['error', { minScore: 1 }],

        // Specific audit scores
        'first-contentful-paint': ['error', { maxNumericValue: 2000 }],
        'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
        'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
        'total-blocking-time': ['error', { maxNumericValue: 300 }],

        // Resource budgets
        'resource-summary:script:size': ['error', { maxNumericValue: 300000 }],
        'resource-summary:image:size': ['error', { maxNumericValue: 500000 }],
        'resource-summary:document:size': ['error', { maxNumericValue: 50000 }],

        // Pass/fail audits
        'uses-http2': 'error',
        'uses-long-cache-ttl': 'warn',
        'offscreen-images': 'off',
      },
    },
  },
}

Category assertions cover different audit groups: Performance evaluates speed metrics, Accessibility checks usability standards, SEO validates search optimization, and Best Practices ensures modern web standards.

Core Web Vitals assertions target key user experience metrics. When these fail, see metric-specific guides: LCP, CLS, INP.

Assertion Levels

  • 'error' - Fails the build
  • 'warn' - Logs warning but doesn't fail
  • 'off' - Disables the assertion

Aggregation Methods

Control how multiple runs are combined:

module.exports = {
  ci: {
    assert: {
      // How to aggregate multiple runs
      // 'optimistic' (default), 'median', 'pessimistic', 'median-run'
      aggregationMethod: 'median',

      assertions: {
        'first-contentful-paint': ['error', {
          maxNumericValue: 2000,
          aggregationMethod: 'pessimistic', // Override for this audit
        }],
      },
    },
  },
}
  • median - Middle value across runs (recommended for stability)
  • optimistic - Best value across runs (preset default)
  • pessimistic - Worst value across runs (strictest)
  • median-run - All values from the median run
Why median? Since the performance score is already a weighted average, taking the mean of scores compounds outlier effects. Lighthouse CI calculates median by finding the run closest to median FCP and median TTI (earliest + latest page lifecycle moments), not just the score.
Never run concurrent Lighthouse audits on the same machine. Concurrent runs skew results due to resource contention.

Assertion Syntax

{
  assertions: {
    // Boolean pass/fail
    'audit-id': 'error',

    // Score threshold
    'audit-id': ['error', { minScore: 0.9 }],

    // Numeric threshold
    'audit-id': ['warn', { maxNumericValue: 1000 }],

    // Both score and numeric
    'audit-id': ['error', {
      minScore: 0.8,
      maxNumericValue: 2000,
    }],

    // Custom aggregation
    'audit-id': ['error', {
      maxNumericValue: 2000,
      aggregationMethod: 'pessimistic',
    }],
  }
}

For detailed budget examples, see Performance Budgets.

Upload Options

The upload configuration controls where audit results are stored.

Temporary Public Storage

Free temporary storage hosted by Google (7 days retention):

module.exports = {
  ci: {
    upload: {
      target: 'temporary-public-storage',
    },
  },
}

Returns a public URL to view results.

LHCI Server

Upload to your own Lighthouse CI server:

module.exports = {
  ci: {
    upload: {
      target: 'lhci',
      serverBaseUrl: 'https://lhci.example.com',
      token: process.env.LHCI_TOKEN, // Build token from server

      // Optional: ignore status code failures
      ignoreDuplicateBuildFailure: true,
    },
  },
}

See LHCI Server Setup for server configuration.

Filesystem

Save results to local files:

module.exports = {
  ci: {
    upload: {
      target: 'filesystem',
      outputDir: './lhci-reports',

      // Optional: report formats
      reportFilenamePattern: '%%PATHNAME%%-%%DATETIME%%-report.%%EXTENSION%%',
    },
  },
}

Multiple Targets

Upload to multiple destinations:

module.exports = {
  ci: {
    upload: {
      target: ['lhci', 'filesystem'],
      serverBaseUrl: 'https://lhci.example.com',
      token: process.env.LHCI_TOKEN,
      outputDir: './lhci-reports',
    },
  },
}

Server Options

Configuration for running your own LHCI server.

Basic Server

module.exports = {
  ci: {
    server: {
      port: 9001,
      storage: {
        sqlDialect: 'sqlite',
        sqlDatabasePath: './lhci.db',
      },
    },
  },
}

PostgreSQL Storage

module.exports = {
  ci: {
    server: {
      port: 9001,
      storage: {
        sqlDialect: 'postgres',
        sqlConnectionUrl: 'postgresql://user:pass@localhost:5432/lhci',

        // Optional: SSL configuration
        sqlConnectionSsl: true,
        sqlDialectOptions: {
          ssl: {
            rejectUnauthorized: false,
          },
        },
      },
    },
  },
}

MySQL Storage

module.exports = {
  ci: {
    server: {
      port: 9001,
      storage: {
        sqlDialect: 'mysql',
        sqlConnectionUrl: 'mysql://user:pass@localhost:3306/lhci',
      },
    },
  },
}

Basic Authentication

module.exports = {
  ci: {
    server: {
      port: 9001,
      basicAuth: {
        username: 'admin',
        password: process.env.LHCI_ADMIN_PASSWORD,
      },
      storage: {
        sqlDialect: 'sqlite',
        sqlDatabasePath: './lhci.db',
      },
    },
  },
}

Build Context

Lighthouse CI can automatically detect CI environment information. Override or supplement with environment variables:

# Git branch
LHCI_BUILD_CONTEXT__CURRENT_BRANCH=main

# Commit hash
LHCI_BUILD_CONTEXT__COMMIT_SHA=abc123

# Commit message
LHCI_BUILD_CONTEXT__COMMIT_MESSAGE="feat: add new feature"

# Author information
LHCI_BUILD_CONTEXT__AUTHOR=user@example.com

# Avatar URL
LHCI_BUILD_CONTEXT__AVATAR_URL=https://github.com/user.png

# PR or build number
LHCI_BUILD_CONTEXT__EXTERNAL_BUILD_URL=https://github.com/org/repo/pull/123

# GitHub repository slug
LHCI_BUILD_CONTEXT__GITHUB_REPO_SLUG=org/repo

Auto-detected in:

  • GitHub Actions
  • Travis CI
  • CircleCI
  • GitLab CI
  • Jenkins
  • AppVeyor
  • Azure Pipelines

Configuration Examples

Single Page App

module.exports = {
  ci: {
    collect: {
      staticDistDir: './build',
      url: ['http://localhost/index.html'],
      numberOfRuns: 5,
    },
    assert: {
      preset: 'lighthouse:no-pwa',
      assertions: {
        'categories:performance': ['error', { minScore: 0.9 }],
        'first-contentful-paint': ['error', { maxNumericValue: 2000 }],
        'speed-index': ['error', { maxNumericValue: 3000 }],
      },
    },
    upload: {
      target: 'temporary-public-storage',
    },
  },
}

These assertions measure initial load speed. For optimization strategies, see the FCP and Speed Index definitions.

Multi-Page Site

module.exports = {
  ci: {
    collect: {
      startServerCommand: 'npm run serve',
      url: [
        'http://localhost:8080/',
        'http://localhost:8080/products',
        'http://localhost:8080/about',
        'http://localhost:8080/contact',
      ],
      numberOfRuns: 3,
      settings: {
        preset: 'desktop',
      },
    },
    assert: {
      preset: 'lighthouse:recommended',
      assertions: {
        'categories:performance': ['warn', { minScore: 0.85 }],
        'categories:accessibility': ['error', { minScore: 0.95 }],
        'categories:seo': ['error', { minScore: 1 }],
      },
    },
    upload: {
      target: 'lhci',
      serverBaseUrl: process.env.LHCI_SERVER_URL,
      token: process.env.LHCI_TOKEN,
    },
  },
}

Production Site Monitoring

module.exports = {
  ci: {
    collect: {
      url: ['https://example.com/'],
      numberOfRuns: 5,
      settings: {
        preset: 'desktop',
        throttling: {
          rttMs: 40,
          throughputKbps: 10240,
          cpuSlowdownMultiplier: 1,
        },
      },
    },
    assert: {
      assertions: {
        'categories:performance': ['error', { minScore: 0.95 }],
        'first-contentful-paint': ['error', { maxNumericValue: 1500 }],
        'largest-contentful-paint': ['error', { maxNumericValue: 2000 }],
        'cumulative-layout-shift': ['error', { maxNumericValue: 0.05 }],
        'total-blocking-time': ['error', { maxNumericValue: 200 }],
      },
      aggregationMethod: 'pessimistic',
    },
    upload: {
      target: ['lhci', 'filesystem'],
      serverBaseUrl: process.env.LHCI_SERVER_URL,
      token: process.env.LHCI_TOKEN,
      outputDir: './reports',
    },
  },
}

Strict production budgets require optimization across all Core Web Vitals. Target values: LCP under 2.5s, CLS under 0.1, TBT under 200ms.

Authenticated Pages

// lighthouserc.js
module.exports = {
  ci: {
    collect: {
      url: [
        'http://localhost:3000/dashboard',
        'http://localhost:3000/profile',
      ],
      startServerCommand: 'npm start',
      puppeteerScript: './scripts/login.js',
      numberOfRuns: 3,
    },
    assert: {
      preset: 'lighthouse:recommended',
    },
    upload: {
      target: 'temporary-public-storage',
    },
  },
}
// scripts/login.js
module.exports = async (browser, context) => {
  const page = await browser.newPage()
  await page.goto('http://localhost:3000/login')
  await page.type('#email', 'test@example.com')
  await page.type('#password', 'password123')
  await page.click('button[type="submit"]')
  await page.waitForNavigation()
}

CI Integration

GitHub Actions

- name: Run Lighthouse CI
  run: |
    npm install -g @lhci/cli
    lhci autorun
  env:
    LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
    LHCI_TOKEN: ${{ secrets.LHCI_TOKEN }}

See GitHub Actions Integration.

GitLab CI

lighthouse:
  script:
    - npm install -g @lhci/cli
    - lhci autorun
  variables:
    LHCI_TOKEN: $LHCI_TOKEN

See GitLab CI Integration.

Next Steps