All articles

Custom CRM

Compare Estimated vs Actual Job Costs: 7 Steps

A variance report can only compare lines that exist on both sides. The 3 ways it silently fails, and the rate vs quantity split that makes it useful.

Om Patel 16 min read
Photo: William Warby / Unsplash

The short answer

Compare estimated and actual job costs by forcing both sides into the same cost buckets, then splitting every gap into a rate variance and a quantity variance. One number tells you the job went over. Two numbers tell you whether you priced it wrong or built it slow, which are different problems with different owners.

The short answer

You compare estimated and actual job costs by forcing both sides into the same cost buckets, comparing bucket by bucket instead of in total, and then splitting each gap into two numbers: how much came from paying a different price than you assumed, and how much came from using a different quantity than you assumed.

That second step is the one almost every contractor skips, and it is the one that makes the exercise worth doing. A single total variance tells you a job disappointed you. The rate and quantity split tells you whether the fix belongs to whoever writes the estimates or whoever runs the crew.

Before any of that, though, there is a structural problem that quietly voids most estimate versus actual reports, and it is worth understanding first because no amount of arithmetic fixes it.

Why does my report say the job was fine when it lost money?

Because the cost that leaked never had an estimated line to vary from. A variance is a comparison, and a comparison needs two sides. If a cost appears in your actuals with no counterpart in the estimate, the report does not flag it as an overrun. It has nothing to flag it against.

This is not a theoretical edge case. In a widely discussed thread on r/sweatystartup, an owner running an eight year old HVAC company with 18 technicians laid out a job he expected to clear over 30% that landed at 8%. His own list of what went wrong: a warranty callback, refrigerant overage, drive time he billed on site hours only, and a day of equipment rental he forgot to quote. As one commenter put it bluntly, not including the rental, drive time or refrigerant is a quoting problem rather than an efficiency problem. Every one of those four costs was real, and not one of them had an estimated line.

There are three distinct ways the comparison fails silently. It is worth checking all three before you conclude your crews are slow.

1. The missing line. The cost exists in your actuals and nowhere in your estimate. Disposal fees, consumables, permit expediting, restocking charges, a return trip for a part, the callback three weeks later. These land in a catch-all bucket or in overhead, and the variance report never mentions them.

2. The different shape. Your estimate is built the way you sell work: by room, by phase, by scope. Your actuals arrive the way money leaves: by vendor, by account, by receipt. A contractor on r/Contractor running QuickBooks Desktop Contractor Edition described exactly this, saying it "basically isn't suited for GC work where we have to tally different receipts and vendors" and that the only reliable route was building the comparison worksheets himself. When the two sides have different shapes, you can reconcile a total but you cannot read a line.

3. The different clock. Actuals are usually recorded when a bill is entered, not when the money is committed. A purchase order issued on Monday, a sub booked for next week, a lift picked up this morning: all committed, none visible for two to four weeks. This is why a job can look healthy right up until it does not.

Watch out

Test your own report in five minutes. Take the last job that disappointed you, list every cost that actually hit it, and tick the ones that had a matching estimated line. The unticked ones are your real leak, and no variance report will ever find them for you, because there is nothing there to vary from.

How do I make the estimate and the actuals comparable?

You define one short bucket list and force both sides into it before anything else. Not a 40 code cost structure, which small shops abandon within a quarter. Five to eight buckets that survive contact with a Friday afternoon.

A workable set for a trade business:

  1. Labor hours (the count, kept separate from dollars)
  2. Labor cost at a fully burdened rate
  3. Materials
  4. Subcontractors
  5. Equipment and rentals
  6. Permits, fees and disposal
  7. Travel and return trips
  8. Warranty and callback allowance

Buckets 5 through 8 are the ones most estimates omit, which is exactly why they belong on the list. Even if the number you put in some of them is zero, a zero is a comparable line and a blank is not. Several operators in the r/sweatystartup thread landed on the same fix independently: a quote template per job type that already contains every possible line, including the ones deleted 90% of the time, so estimating becomes scanning a list rather than remembering from scratch.

Two rules make the buckets hold:

Use a burdened labor rate on both sides. An accountant in r/Contractor named this as the single most common margin killer he sees: contractors not using a burdened rate in their estimates for job costing purposes. If your estimate uses the $28 base wage and your actuals carry $44 of wage plus payroll taxes plus workers compensation plus benefits, every job you have ever reviewed showed a fake labor overrun and you have been chasing a crew that was never the problem.

Set up the job before the first cost hits it. Costs that arrive before a job record exists get coded somewhere else and rarely get moved. If your books are the place your actuals live, the mechanics of that setup order are covered in setting up job costing in QuickBooks Online, and the specific reasons costs go missing from job reports are covered in QuickBooks not tracking job profitability.

What does the comparison actually look like?

Here is a worked example: a residential electrical service panel upgrade, sold at $5,400.

BucketEstimatedActualVariance
Labor hours24 hrs31 hrs+7 hrs
Labor cost (burdened)$1,392 @ $58/hr$1,953 @ $63/hr+$561
Materials$2,100$2,310+$210
Permits and fees$180$180$0
Disposalnot estimated$95undefined
Total direct cost$3,672$4,538+$866
Revenue$5,400$5,400$0
Gross margin32.0%16.0%-16.0 pts

Sixteen margin points gone on a job where the customer paid exactly what was quoted. Notice the disposal row: the variance is not $95, it is undefined, because there was no estimate to compare against. That distinction matters, because a missing line is an estimating template failure and it will repeat on every panel upgrade you quote until someone adds the line.

Now the part that turns this table into decisions.

How do I split a variance into rate and quantity?

Every cost is a price multiplied by a quantity, so every variance has a price component and a quantity component. Cost accounting has clean formulas for this, and they work unchanged on a trade job.

Labor rate variance = actual hours x (actual rate - estimated rate)

Labor efficiency variance = estimated rate x (actual hours - estimated hours)

Applied to the panel upgrade above:

  • Rate variance: 31 x ($63 - $58) = $155
  • Efficiency variance: $58 x (31 - 24) = $406
  • The two sum to the $561 total labor gap, which is how you know you did it right.

The materials gap splits the same way. Here the crew used exactly the quantities that were estimated and the supplier invoice simply came in higher than the six week old quote, so the entire $210 is a price variance and the usage variance is zero.

So the honest breakdown of "$866 over" is:

ComponentAmountWhat it actually meansWho owns it
Labor efficiency$406Took 7 hours longer than the standardProduction, or a wrong standard
Labor rate$155Staffed richer or ran overtimeScheduling
Material price$210Supplier moved between quote and buyPurchasing, or quote expiry terms
Material usage$0Quantities were rightNobody, this one is fine
Disposal$95Never on the estimateThe estimating template

Four numbers, four different owners, four different fixes. A single "$866 over budget" would have sent you to a crew meeting about productivity, when only $406 of it was productivity, and $460 of it was fixable at a desk before the job ever started.

Tip

Read the two labor variances together, not separately. Cheaper hourly rate plus more hours is the classic sign of staffing down: you saved on the rate and paid it back on the clock. Higher rate plus fewer hours is often a good trade, and the only question is whether the time saved was worth the premium.

Most contractors know how to do this arithmetic. What they do not have is the estimate and the actual hours sitting in the same system on a Friday. We build custom CRMs for trade businesses where the quote, the crew's logged hours, the material receipts and the change orders share one job record, so estimated versus actual is a screen rather than a weekend spreadsheet rebuild.

Book a free CRM demo

How do I compare estimate to actual mid job?

By converting cost to date into a projected final cost, because spend against budget on its own tells you nothing. Spending 60% of the budget is excellent at 80% complete and a disaster at 30% complete, and the raw percentage cannot distinguish the two.

Projected final cost = cost to date / percent complete

Take the panel upgrade at the end of day two. Cost to date is $2,600 against a $3,672 budget, which looks like a comfortable 71%. Then you ask the lead what fraction of the work is done and he says roughly 55%. Projected final cost is $2,600 / 0.55 = $4,727, a 29% overrun, visible on day two with a day of work left to change the outcome.

Level, a construction accounting firm, publishes a blunter version of the same guardrail: flag any job that hits 80% of its budgeted cost before 60% of the work is complete. It requires nothing but a cost figure and a foreman's honest estimate of completion, and it catches the failure mode that costs the most.

That timing is the whole game. A window and door contractor posting on r/Contractor described finding out he made 8% on a job he thought was 25%, and discovering it six weeks after the job ended. Six weeks is not a management report, it is an autopsy, and in the meantime every quote written from those assumptions carried the same hole. Another operator in that thread was direct about the alternative: people underestimate how much of a difference it makes to track costs during the project rather than after the fact.

Should change orders count as an overrun?

No, and getting this wrong is how good estimators get talked into padding bids that were already correct. An approved scope change is a customer decision, not an estimating error. It belongs on the estimate side of the comparison before you calculate a single variance.

A contractor on r/Contractor described a clean way to keep this straight: when scope changes, he issues a revised estimate containing new line items that state what changed and why, with fine print noting that it supersedes all previous estimates. There is always exactly one current baseline, and the variance is always measured against it.

The version that eats margin is the one that never becomes a change order at all. The tech is on site, the customer asks for one more thing, and it is faster to do it than to argue. Level's analysis of contractor job data names this as the silent margin killer: the budget stays the same, the cost goes up, and the shortfall gets attributed to slow crews at year end. Their observation from the tightest performing contractors is that every one of them prices and approves out of scope work before it happens, not at invoicing.

Which variances are worth chasing?

The ones that are both large and repeating. Chasing everything is how a review habit dies in three weeks.

Two thresholds that hold up in practice:

  • At the line level, standard cost accounting practice is to investigate a rate variance above roughly 3% to 5% of standard, and an efficiency variance above roughly 5% to 10%. Below that you are usually measuring noise.
  • At the portfolio level, Level suggests landing within plus or minus 15% of budgeted labor hours on 80% of jobs as a strong target for most $3M to $30M contractors, with the best performers in their data inside 10%.

Then narrow the scope of what you watch weekly. One contractor in the r/Contractor margins thread described tracking only the three highest cost items religiously every week, in his case waste disposal, labor and equipment, on the grounds that the rest genuinely is not as big a problem. That is a better system than a comprehensive review nobody runs.

By the numbers

Level's dataset of 315,393 jobs from 1,391 contractors found 40% of jobs exceeded their budgeted labor hours and 18.3% ran past 150% of them, while the 25th percentile came in at 70.1% of budget. Chronic under-runs are a problem too: consistently landing 30% under budget means padded bids and lost work, and it hides the disasters inside a portfolio average that reads fine.

How do I feed the result back into the next estimate?

By changing the template, not the judgment, and only when the same variance shows up repeatedly.

The rule to hold: one job is a data point, a pattern is a standard. A blown shipment that cost you overnight freight does not belong in your permanent material rate. Fifteen consecutive jobs running 20% over on labor hours does belong in your labor standard. Level's own guidance on this is to review the five most over budget and five most under budget jobs monthly, because the under-budget ones tell you where your estimates are padded, which is worth money in competitive bids.

The mapping from variance type to fix is direct:

What you see repeatedlyWhat to change
Efficiency variance on one job typeThe estimated hours in that job type's template
Rate variance from overtimeScheduling and crew mix, not the bid
Material price varianceQuote expiry terms, or an escalation clause on jobs starting past 30 days
Material usage varianceThe waste allowance, or purchasing and staging
Costs with no estimated lineThe template itself, permanently
Nothing at all, but margin fadesYour burden rate, or costs landing outside the job

Two practical additions from operators who had already been burned. Several in the r/sweatystartup thread build a standing allowance for the predictable non-surprises: a multiplier of 1.1x to 1.15x on estimated hours for drive time in commercial work, and a small job contingency of 2% to 3% of cost for the one-off bleeds. Neither is padding. Both are pricing a cost that reliably occurs.

The other addition is a ten minute debrief before the crew leaves site: anything used that was not on the estimate, any likely callback, actual hours against budgeted. That information reaching whoever writes the next quote the same day is worth more than a perfect report that arrives a month later. If your quoting happens in a separate tool from your job records, estimating software for contractors covers the options for closing that loop.

The weekly routine

The whole system fits in about 30 minutes a week once the buckets exist.

  1. Every open job: cost to date, percent complete from the lead, projected final cost. Flag anything past 80% of budget before 60% complete.
  2. Every open job: confirm any scope change since last week became a revised estimate. Unbilled scope is not an overrun, it is unbilled revenue.
  3. Every job closed this week: fill in the actual column, calculate the rate and quantity split on labor and materials, and write one sentence per significant variance saying why.
  4. Monthly: the five worst and five best jobs, looking for the same reason appearing more than twice.
  5. Quarterly: move any repeating variance into the estimating template and reset the standard.

None of it works if your buckets are wrong or if your labor rate is unburdened, so fix those first. And do not judge the result on a single job. What you are looking for is not a job that matched its estimate, which is mostly luck, but a distribution that tightens around the estimate over a year, which is a system. For the number that distribution should be tightening around, see how much profit a contracting job should make.

Frequently asked questions

How do I compare estimated vs actual job costs?
Put both sides in the same cost buckets, compare bucket by bucket rather than in total, then split each gap into a rate variance and a quantity variance. Labor rate variance is actual hours multiplied by the difference between the actual and estimated hourly cost. Labor efficiency variance is the estimated hourly cost multiplied by the difference between actual and estimated hours. The two add up to your total labor gap and point at two different problems.
Why does my job cost report say the job was fine when it clearly lost money?
Almost always because the cost that leaked never had an estimated line to vary from. Disposal, drive time, a warranty callback, a one-day equipment rental and consumables are the classic examples. A variance report can only compare lines that exist on both sides, so a cost with no estimated counterpart lands in an other bucket or in overhead and the report stays silent about it.
How often should I compare estimated to actual job costs?
Weekly on any open job, and again within a week of closeout. Weekly is when you can still change the outcome. A window and door contractor on r/Contractor described finding out he made 8% on a job he thought was 25%, six weeks after the job had ended, which is a post mortem rather than management. Contractors with the tightest cost control review the three biggest cost categories every week rather than everything once a month.
What is a good variance percentage on a job?
Level, a construction accounting firm, suggests landing within plus or minus 15% of budgeted labor hours on 80% of jobs as a strong target for most $3M to $30M contractors, with the best in their data running within 10%. For flagging individual line items, a common rule from cost accounting is to investigate a rate variance over 3% to 5% of standard and an efficiency variance over 5% to 10%.
How do I compare estimate to actual while the job is still running?
Never compare spend to date against the total budget on its own, because that number is meaningless without percent complete. Divide cost to date by the fraction of the work finished to get a projected final cost, then compare that to the budget. Level suggests a simple guardrail: flag any job that hits 80% of its budgeted cost before 60% of the work is complete.
Should change orders count as a cost overrun?
No. Approved scope changes belong on the estimate side before you calculate any variance, or you will read a customer decision as an estimating failure and start padding bids that were already correct. One contractor on r/Contractor handles this by issuing a revised estimate with new line items explaining what changed and why, with fine print stating it supersedes all previous estimates, so there is always one current baseline.
Why do my actual costs keep arriving after the job closes?
Because most actuals are recorded when a bill is entered, not when the cost is committed. A purchase order issued, a subcontractor scheduled or a rental picked up are all real money spent that your report will not show for two to four weeks. The fix is to record committed costs against the job at the moment of commitment and let the invoice replace the commitment later.
Do I need software to do estimate versus actual, or will a spreadsheet work?
A spreadsheet works well below roughly five open jobs, as long as one person updates it weekly. It breaks when more than one person needs the current number, when the estimate and the actuals live in different tools, or in the weeks you are busiest, which is exactly when the variance is largest. The failure is rarely the math, it is the data arriving too late to act on.
Bespoke pipelines, automations, 360° customer records and real-time reporting, a CRM built around how your team actually works, connected to your entire stack.
Book a free CRM demo

Free tools

Find out what your site is costing you.

Enter your address and we check the real page. Scores are free and the itemised report lands in your inbox. No account, and we change nothing on your site.