Lesson 81 of 81
A Lighthouse score you check manually is a score you'll forget to check the week it regresses. A performance budget enforced in CI turns 'we should keep an eye on this' into a failed build.
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
A performance budget is a numeric ceiling on something that affects user experience — bundle size, LCP, Total Blocking Time — that the build is not allowed to exceed. Lighthouse CI (@lhci/cli) is the tool that runs Lighthouse against your app in an automated pipeline and fails the job when a budget is broken, instead of just printing a score for a human to glance at and forget.
The reason this needs to be a CI gate and not a habit: a single "just this once" 200KB chart library, added under deadline pressure, doesn't feel like a regression to the person who added it — it feels like normal feature work. Nobody runs Lighthouse locally before every PR. A budget enforced in CI catches exactly the commit that caused the regression, with the diff still fresh, instead of surfacing as "the site feels slower lately" three months later with no idea which of two hundred commits did it.
Lighthouse CI reads a config file describing what to test and what to assert against:
// lighthouserc.js
module.exports = {
ci: {
collect: {
staticDistDir: "./out",
numberOfRuns: 3,
url: ["http://localhost/", "http://localhost/pricing"],
},
assert: {
assertions: {
"categories:performance": ["error", { minScore: 0.9 }],
"largest-contentful-paint": ["error", { maxNumericValue: 2500 }],
"total-blocking-time": ["error", { maxNumericValue: 200 }],
"resource-summary:script:size": ["error", { maxNumericValue: 300000 }],
},
},
upload: {
target: "temporary-public-storage",
},
},
};
numberOfRuns: 3 matters more than it looks like it should — Lighthouse scores vary run to run from ordinary machine noise, and asserting against a single run means a budget check that's flaky by construction. Lighthouse CI takes the median of the three automatically, so the assertions below are checked against a stable number, not whichever run happened to land first.
Wiring it into GitHub Actions so a regression genuinely blocks the merge, not just the deploy:
# .github/workflows/lighthouse.yml
name: Lighthouse CI
on: pull_request
jobs:
lhci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: pnpm install --frozen-lockfile
- run: pnpm build && pnpm exec next export -o out
- run: pnpm dlx @lhci/cli autorun
The critical detail: this runs against a production build (pnpm build), never pnpm dev. Dev mode ships unminified code, unbundled modules, and extra instrumentation — every metric it produces is wrong in the pessimistic direction, so a budget checked against dev output either never fires (masking real regressions) or fires constantly on noise unrelated to anything a reviewer can act on.
next dev. Dev-mode bundles are deliberately unoptimized; a budget checked against them either fires on noise (unminified code always "fails" a tight size budget) or misses genuine regressions the minified build would have exposed.numberOfRuns: 3 (or more) and taking the median is what makes the assertion trustworthy instead of flaky.resource-summary:script:size directly closes that gap."Your team shipped a chart library last sprint and now LCP is failing your SLA in production — how do you make sure this doesn't happen silently again?" tests whether a candidate's answer is a process ("we should be more careful reviewing PRs") or a mechanism (a CI-enforced budget that fails the specific PR that regresses it). The strongest candidates volunteer that the check has to run against a production build and account for run-to-run variance, not just that "Lighthouse should run in CI" as a vague gesture.