Your Job Costing Is Built on Guesses — Not Last Year's Jobs
Your Job Costing Is Built on Guesses — Not Last Year's Jobs
In 2019, I pulled the P&L on a 14-truck residential HVAC shop that Atlantic Comfort Partners was preparing to acquire. The owner had been in business for nineteen years. He had job cost data — tickets, invoices, a field management platform he'd been paying for since 2016. What he didn't have was any mechanism for comparing what he estimated against what jobs actually cost to run. He had been losing money on every install for three years. He had no idea.
That shop is the reason I write about job costing more than almost anything else.
The problem wasn't software. Every estimate he wrote was built on assumptions he'd formed around 2014, adjusted occasionally by feel, never verified against a closed job. The data existed in his system. The loop was never closed, so the error didn't just persist. It compounded, quietly, for years.
The Estimate Was Wrong Before You Touched the Keyboard
Most shops I work with think they have a job costing problem. What they actually have is a data collection problem, dressed up as a costing problem because that's where the symptom shows.
You price a job using a markup you've always used — maybe 35% on equipment, maybe a flat labor rate you set a few years ago, a rough hours estimate based on what similar jobs felt like. The job runs. You collect payment. You move on. You never formally compare what you estimated to what the job actually cost to complete.
Next time a similar job comes in, you estimate it the same way. Because why wouldn't you? You finished the last one and the customer paid.
This is not job costing. This is pattern recognition built on unverified memory.
The cost-of-doing-business calculation — what it actually costs per billable hour to keep a truck on the road, pay a technician, cover overhead, and produce a dollar of revenue — is the foundation every estimate sits on. Most small shops have never run that number formally. They've adopted a markup convention and assumed the margin comes out right. Those are different things. Markup is what you add to cost. Margin is what's left after you cover everything. Shops confuse the two and discover the distinction too late.
Where Most Shops Stop Short
A functioning job costing cycle requires four things: an estimate, actuals collected during the job, a comparison, and a variance fed back into the next estimate. Almost nobody runs all four stages.
At Bayview Mechanical, techs finished work and closed tickets. Nobody tracked actual hours by task — hours got logged to the job in a lump, if at all. Material pulls weren't tied back to job numbers. Change orders, extra scope absorbed in the field because the tech wanted to be helpful or because calling the office felt awkward, disappeared into job cost without record. The data that would close the loop was never generated. Not because the tech was lazy. Because the system didn't ask for it in a form that made collection easy. Caldera was structured the same way. Different software, same missing stage.
Before you can fix that, know which margin you're actually measuring. Gross margin is revenue minus direct job costs: labor, materials, equipment, subcontractors. Contribution margin is revenue minus costs that exist only because the job exists — it excludes fixed overhead entirely. The difference matters because overhead allocation — shop rent, office staff, truck depreciation, insurance — determines whether a job that looks profitable on the surface is actually covering its share of fixed costs.
Most shops running informal job costing are measuring something closer to contribution margin and calling it gross margin. The overhead is still there. It's just not assigned.
Why Gut Feel Gets Worse Over Time, Not Better
Estimating from memory doesn't produce consistent inaccuracy. It drifts. And it drifts in a predictable direction.
Labor hours and overhead burden both rise over time, faster than an estimator's mental baseline updates. You know roughly what a standard changeout took in 2021. You're probably still using something close to that number, adjusted maybe 10% in your head, even though your tech's fully burdened hourly cost has increased materially and the job has gotten more complicated as systems have changed.
The SEER2 transition made this visible. Shops that absorbed equipment cost increases without updating their install pricing did so in part because their estimate templates never caught the delta. The equipment line got updated because it had to — the distributor invoice forced it. The labor estimate didn't, because that number lived in the estimator's head. The gut-feel number didn't adjust. It just became more wrong.
Most estimators update the costs they can see on an invoice. They don't update the costs they carry in their heads, and those are the ones compounding against you.
Truck operating cost is the clearest case. The single most underpriced cost in residential HVAC. An estimator working from a mental number formed 18 to 24 months ago is almost certainly using fuel and insurance figures that don't reflect current reality. Commercial auto premiums in Virginia ran 18 to 22% annual increases for two consecutive years in the shops I audited — the margin buffer most owners had wasn't close to absorbing that. When the truck cost is wrong, every estimate built on it is wrong. Every one.
The Contrarian Position: Better Software Won't Fix This
The instinct, when you identify a job costing problem, is to buy something. Every major field management platform — ServiceTitan, Jobber, the rest — has a job costing module. Real features, real capability.
They also require accurate actuals input to produce accurate output. That's not a criticism of the software. It's a description of how data works.
ServiceTitan's reporting suite is excellent for a shop with a dispatcher, a real service department, and someone with the time and training to build the reports. Above roughly 12 trucks, the per-user cost clears the bar. Below that, I've consistently watched the job costing module collect dust next to the unused reporting suite, because the implementation consultant who configured it is long gone and nobody on the team knows how to maintain it. The shops I've audited with the cleanest job costing practices are often on simpler platforms or structured spreadsheets. Not because simple is better, but because the discipline of recording actuals is a human system.
The form the tech fills out before closing a work order, the 15-minute weekly review the office manager runs — those are not software features. They're habits. You can run them in a Google Sheet. You can also fail to run them in ServiceTitan.
Buy the software when you've outgrown your current system. Don't buy it to manufacture a discipline you haven't built yet.
What Closing the Loop Actually Looks Like
A residential HVAC shop I audited a couple of years into my consulting practice — nine trucks, owner-operator who had been estimating off the same mental model since he launched — was a skilled estimator by feel. When I asked him what his average labor hours were on a standard split-system changeout in a two-story home with an attic air handler versus a single-story slab application, he paused. He said they were probably about the same.
They were not.
We introduced a simple post-job form: actual hours by task, actual materials pulled, any change-order scope that got absorbed. One page, field sheet, shared folder, completed by the tech before closing the work order. Within 90 days we had enough closed jobs to run a comparison.
His changeout labor estimates were running 22% low on two-story homes with attic air handlers. Every one. He had been pricing those jobs as if they were slab installs because that's what his mental model averaged across all his install experience. The attic work — staging equipment, second trips for refrigerant, the awkward geometry of confined spaces — was getting absorbed as unbilled labor on every single one.
Something else surfaced once the actuals were being recorded. The shop could now see which job types had the worst cash conversion. Warranty callbacks on systems sized by rule of thumb rather than Manual J were landing well after the invoice closed. The job looked done. The cost wasn't. Days sales outstanding — the average time between completing a job and actually collecting on it — was being distorted by jobs that generated callbacks the shop couldn't bill for. They couldn't see any of it until the actuals were on paper.
What to Do Monday Morning
You don't need a new platform. You need three closed jobs and a few hours.
Pull three jobs from the last 60 days. For each one, reconstruct actual cost from what you have: tech logs for hours, material invoices, your best truck cost approximation for windshield time. Apply your fully loaded hourly rate — burden included, not just wage. Include overhead allocation at whatever percentage your cost-of-doing-business calculation produces.
Compare that reconstructed actual cost to what you estimated. Write down the variance in dollars and as a percentage.
If actual came in more than 10% above your estimate, that job gets reviewed before you write the next similar one. Fifteen minutes, you and whoever writes estimates, looking at where hours or materials ran long. That's it. Build the habit forward. The post-job form doesn't have to be elegant. It has to be consistent.
The 14-truck shop from 2019 had the data sitting in a system it had been paying for since 2016. They never closed the loop. Three years of compounding error, and none of it showed up as a line item on the P&L — it was distributed across labor and vehicle expense, invisible until someone sat down to look.
You can look now.
FAQ
My techs are in the field all day — how do I get them to record actuals without a fight?
Tie the form to closing the work order. If the tech can't close the ticket without completing three fields — actual hours on-site, materials pulled, scope that ran beyond the estimate — it becomes part of the routine rather than extra work. The forms that generate pushback are the ones that take 15 minutes. Keep it under five. The resistance is almost always about length, not concept.
How many closed jobs do I need before my estimates start being reliable?
By job type, not in aggregate. Ten to fifteen closed jobs of a given type — standard changeout, new installation, service call with repair — before the actuals average stabilizes enough to use as a baseline. If you run 20 installs a month, you can have useful data within 60 days. Start now. The data doesn't exist until you begin generating it.
Isn't this what my accounting software does automatically?
QuickBooks can produce a job profitability report — but only if labor is coded to a job number, materials are coded to a job number, and the job number connects to an estimate. Most shops under 15 trucks don't have that coding discipline in place. The accounting software records what it's told. It shows revenue and expense. It doesn't tell you whether the estimate was right. That bridge between estimate and actuals is the discipline, not the software.
What's the difference between job costing and looking at profit per invoice?
Invoice profit shows revenue minus whatever costs happened to get coded to that job. Actual job costing shows revenue minus everything — overhead allocation, truck operating cost per hour, any unbilled labor absorbed in the field. Invoice profit almost always looks better than actual job margin because absorbed costs are invisible to it. It's a number that flatters you. Pricing decisions made from it tend to be decisions you'll revisit under pressure.
I've been estimating the same way for 11 years and I'm still in business — how bad can the error be?
The owner I looked at in 2019 had been in business for nineteen years. Still in business is not the same as margin where you think it is. What I typically find: volume covering losses on individual job types, the service side subsidizing the install side, or an owner working more hours than the profit justifies. When costs rise faster than the mental baseline updates — and they have, materially, over the past three years — the gap widens. The business survives. The owner earns less than the numbers suggest.
Should I job-cost maintenance agreements the same way I cost installs?
Yes. Most shops don't. A maintenance agreement is a fixed-price commitment to deliver a variable amount of labor and materials across multiple visits. Without tracking actual hours and parts cost per visit, you don't know whether the agreement is profitable — you only know whether customers renewed. The number I've seen in shops where I've tracked it: agreement visits with deferred work discovered run 35 to 40% over the budgeted labor time, and the follow-up repair typically comes back at a discount because the customer expects preferential pricing. Track the actuals on agreements the same way you track them on installs. You may find the agreement price is subsidizing work you're not accounting for.
Enjoyed this article?
Get articles like this in your inbox every Monday. Free, no spam.
