Before the Mug Goes Cold: A Team Budget for Local Build Speed
Photo: Parker Byrd parkerabyrd, CC0, via Wikimedia Commons
Every team has a version of the same conversation. Someone saves a file, leans back, watches the spinner, and says: “I’ll put the kettle on, then.” It gets a laugh. It also gets treated as an unavoidable fact of life, like rain on a bank holiday. But local build speed is not just a personal annoyance. It is a shared budget that your team spends every day, and most teams have never actually looked at the receipt.
That is the case for treating the local feedback loop as a team concern rather than a hero project. Not a six-week performance epic led by one person who enjoys flame graphs. A quiet, ongoing budget: measured, agreed, protected and improved in small increments.
Measure the loop, not just the build
Start by defining what you mean by “local feedback loop”. It is rarely just compilation. For most teams it looks something like this: change a file, wait for the build, run the relevant tests, start or reload the app, click through the thing you are working on. The useful measure is the time from save to trustworthy signal.
You do not need a full observability platform for this. A shared spreadsheet and a few deliberate stopwatch runs will do. Ask everyone to time three things over a normal week:
- a small code change to a passing test result in the area they are working on
- the full local test suite on a clean checkout
- setup from clone to a running app on a fresh machine
Record the median and the rough worst case, not just the best run on the newest laptop. A senior developer with a fast machine is not the benchmark. The new starter on a company-issued laptop is the benchmark.
Agree a kettle test
The kettle test is simple: if you can make a brew and be back before the build has finished, the loop is too slow. But a joke is not a target. Turn it into something the team can actually use.
A reasonable starting budget for a typical web or backend service might be:
- save to relevant test result: under 10 seconds for the common path
- full local test suite: under 3 minutes
- fresh setup to running app: under 30 minutes, ideally much less
The numbers matter less than the agreement. Write them down. Put them in the README next to the run commands. Mention them in onboarding. If the team says “three minutes for the full suite is fine for now”, that is a budget. If it creeps to nine minutes, you have a conversation to have.
Find the worst offenders first
Performance work goes wrong when it starts with a grand tour of every possible optimisation. Resist that. Find the three or four waits that hurt most often and fix those first.
Ask each developer for their top three “waiting moments” from the last fortnight. Then look for patterns. Common culprits include:
- a full Docker rebuild for a one-line change
- tests that hit a real database when an in-memory or containerised one would do
- front-end bundling that reprocesses everything on every save
- build caches that are disabled because someone once had a bad experience
- setup scripts that download the internet in serial
Use simple profiling. Time the phases. Run the build twice and compare cold and warm. Use hyperfine or a shell script with date if that is all you have. The point is to replace a vague sense of slowness with a named bottleneck.
Fix one thing per sprint, not everything at once. A faster test subset, a better cache configuration, a smaller dev container image. Small, boring improvements compound.
Make the budget visible without making it personal
Speed work fails when it becomes a competition. Nobody wants to be the person whose laptop is “the slow one”. Keep the conversation about the shared environment, not individual hardware.
A lightweight approach is a build weather note in standup: “Local suite is currently around four minutes on the reference machine; we are over budget because of the new integration tests.” That is it. No blame, no performance review, just a shared signal.
If you have CI, you can also track a nightly timing job on a fixed runner. It will not exactly match local machines, but it will catch the direction of travel. A 20% regression over a month is easier to spot in a chart than in a dozen separate moans.
Put a small guardrail around it
You do not need a formal service-level objective, but you do need something that stops the budget being forgotten the moment the team gets busy. A few options:
- add a line to the pull request template for changes that touch build config, dependency versions or test setup: “Did local loop time change?”
- keep a small benchmark script in the repo and run it before and after build-related changes
- review the timings once a quarter, the same way you review dependencies or on-call load
- treat “fresh setup under 30 minutes” as part of the definition of a healthy repo
The guardrail should be proportional. A two-person team does not need a dashboard. A twenty-person team probably needs one shared number and a named owner for the next improvement.
The cultural bit
A fast local loop is not a luxury. It is how people stay in flow, how new starters become useful, and how small changes stay small. It is also a form of respect: you are not asking people to spend their day watching progress bars.
The opposite is also true. A slow loop teaches people to batch up changes, avoid running tests, and context-switch while they wait. None of that is a character flaw. It is a predictable response to a bad environment.
So treat it like a budget. Measure the loop, agree the kettle test, fix the worst offender, and keep an eye on the trend. No heroics required. Just a team that notices when the mug goes cold before the build goes green.