Trades industry news, updated weekly
Business Tips

Your Gross Margin Is Lying to You Without Job Costing

Maria ChenMaria Chen··12 min read

Your Gross Margin Is Lying to You Without Job Costing

In 2019, I pulled the P&L of a 14-truck residential HVAC shop my firm was preparing to acquire. The owner had 22 years in the trade. His blended gross margin was sitting at 38%. The broker had positioned it as a healthy, profitable operation.

It wasn't. He had been losing money on every install job for three years — meaningful money, per ticket. The install losses weren't a line item anywhere on that P&L. They were distributed across labor and vehicle expense, invisible inside the blend. The service department was subsidizing installs and nobody knew it. Not the owner. Not his bookkeeper. Not the outside CPA. Because nobody had run the numbers by job type.

That's the problem job costing solves. Most small shops aren't doing it.


Why Gross Margin Feels Like Enough (And Isn't)

Blended gross margin is a seductive number. Clean. Single-digit. Fits on a dashboard. A 38% blended margin tells you that for every dollar of revenue, you're keeping 38 cents before overhead and profit. That sounds like information.

What it actually is: an average. The weighted average of every job you closed last month — your strongest maintenance agreements, your profitable ductless mini-split installs, the gas furnace replacement where the apprentice needed four hours of supervision you didn't bill for. All of it folded into one number.

Averages hide distributions. A 38% blended margin is consistent with a service department running at 52% and an install department running at 19%. Those two numbers require completely different responses. The blended number requires none. It looks fine.

There's also the markup-versus-margin confusion that runs through small shops. An owner who prices a job at 1.6x materials thinks he's running a 60% markup, which feels like health. He's running a 37.5% gross margin — before burden, before truck cost, before the two callbacks that didn't get billed. By the time actual job cost is in the denominator, the margin on that ticket might be 18%. He doesn't know, because he priced by markup and measured by blend.

The blended gross margin is a green light at the company level. It is not a green light for individual jobs, individual service lines, or individual technicians. Treating it as one is how you get to year three of losing money on installs.


What Job Costing Actually Measures (And What Most Shops Skip)

Job costing is not complicated. For each closed job, you assign four inputs: materials and equipment at landed cost, direct labor with full burden, any subcontractor costs, and what the truck actually cost on that job.

That last input is where most shops fall apart.

Truck operating cost per billable hour is, in my view, the most underpriced single input in residential contracting. Most owners who do any cost calculation at all pull a figure from some industry publication. That number is a fiction for their shop — their insurance rates, their fuel costs, their vehicle age, their local dispatch density are specific to them.

When I run the actual truck cost in a shop engagement — fleet insurance allocated across billable hours, fuel at local current prices, maintenance reserve, registration, depreciation — the number is almost always higher than the owner expected. Sometimes significantly. That gap, multiplied across every job in the month, is where margin disappears.

A definitional note worth being precise about: job costing is not general ledger accounting. Your general ledger tracks revenue and expenses by category across the whole business. Job costing tracks those same inputs by individual job or job type, so you can see the margin on a maintenance agreement separately from an equipment install separately from a diagnostic call. Your accountant is doing the first thing. For most shops, nobody is doing the second.


The Service Line Problem: Installs vs. Service vs. Maintenance

The distortion gets worse when you separate service lines. Residential trade shops typically run three businesses inside one legal entity: equipment installs, service and repair, and preventive maintenance agreements. Those three lines have different cost structures, different labor intensities, different truck utilization, and different margin profiles. Blending them produces a number that describes none of them accurately.

At Atlantic Comfort Partners, I ran acquisition analysis on shops across the mid-Atlantic and Southeast. A target would report a blended gross margin that looked acceptable. When we rebuilt the P&L by service line — allocating overhead proportionally, assigning actual truck cost per job type, separating install labor from service labor — the install gross margin consistently came in several points below the company-reported number. The service department's stronger margin was covering the gap. The acquirer saw it. The owner hadn't.

The SEER2 transition made this worse for shops that didn't reprice installs when the cost basis changed. Shops that absorbed the equipment cost increase and passed through their standard markup compressed their install margins on every ticket. In my consulting work since 2021, I've seen this pattern in a majority of the shops I've audited — they took the hit on margin rather than reprice, and the blended number still looked acceptable because service held up. Job-level costing is the only way to see that compression before it runs for two years undetected.


The Real Story: A Shop That Didn't Know Which Jobs Were Killing It

Back to the 14-truck shop. When I pulled the P&L as filed, the install department looked like it was contributing. Labor was in COGS. Materials were in COGS. Truck expense rolled up with service and maintenance truck costs together, undifferentiated. The install losses weren't visible because they weren't isolated anywhere.

I rebuilt the P&L by job type. Three months of closed jobs from the field management software, actual labor hours and burden by job, truck cost at the shop's real operating rate rather than the owner's estimated average, install material cost separated from service parts cost.

The install department, in isolation: 21% gross margin. Service department: 49%. Maintenance agreements: 61%. The blended 38% was mathematically correct. It was also the reason nobody had caught this.

The same mechanic shows up in diagnostic call pricing. I've written about this elsewhere, but the short version: a shop charging $89 for a diagnostic call isn't necessarily wrong to price it as a loss leader, but they need to know what the actual loss is. When you allocate real truck operating cost, burden-loaded technician time, and windshield time per call, the absorbed cost on a sub-$100 diagnostic ticket often exceeds what the shop charged. At volume, that's not a pricing opinion. It's a structural problem the blended margin will never surface.


Contrarian Take: Your Accounting Software Isn't the Problem

The standard explanation for why small shops don't job-cost is that the software doesn't support it, or the module is complicated, or the implementation costs too much.

That explanation is convenient. It's mostly wrong.

ServiceTitan's job cost reporting, when actually configured, would give a 10-truck shop more margin visibility by job type than most companies ten times their size have. The problem is that nobody built those reports. The implementation consultant configured the system at go-live and left. The owner has been too busy to learn how to run them. Capability that nobody operationalizes is shelf software, not a job costing system.

The flat-rate pricing book tells you what to charge per ticket. It does not tell you whether the ticket made money. Those are different questions, and only one of them matters for the long-term health of the shop.

The price book gives you consistent revenue per ticket, calibrated to what the market will bear — not to your cost structure. Your labor burden rate is not the same as the shop in the next county. Your truck cost is not a national average. The price book cannot account for those differences. Job costing does.

The real reason most shops avoid job costing is that the output is often inconvenient. An owner who has been telling himself and his bank that installs are profitable does not want a spreadsheet showing they aren't. That avoidance is understandable. It's also how you get to year three of subsidizing installs with service margin and calling the blended number a success.


What to Do Monday Morning: A Minimum Viable Job Costing Setup

You do not need a software implementation or a new accounting system to start. You need a spreadsheet and last month's closed jobs.

Four inputs, one sentence each:

Direct labor with full burden. The technician's hourly wage plus payroll taxes, workers' comp allocation, health insurance contribution, and PTO accrual — the actual cost to have that person working an hour, not the wage on the timesheet. The BLS Employer Costs for Employee Compensation data puts total benefit cost at roughly 30-32% of wages for private-sector trade workers nationally; your actual number will differ, so pull it from your own payroll records rather than using a benchmark.

Materials and equipment at landed cost. What you paid, including freight. If you returned a part and paid a restock fee, that goes here.

Truck operating cost at your actual rates. Pull your last 12 months of fleet insurance, fuel, and maintenance costs. Add annual depreciation. Divide by total billable truck-hours for the year. Not a benchmark. Your number.

Overhead allocation per job hour. Total your monthly fixed overhead — rent, utilities, office staff, software subscriptions, owner's market-rate salary — and divide by total monthly billable hours. Apply that rate to hours logged per job. It's not perfect cost accounting. It gets overhead into the job rather than leaving it as an unallocated lump that makes individual job margins look better than they are.

Run those four inputs against 20 closed jobs from last month, spread across at least two service lines. The margin difference between lines will likely surprise you.

One more check while you have the data open: cross the job cost results against your accounts receivable aging by job type. In the shops I've audited, the service lines with the worst job-level margin tend to sit in the 60-plus-day receivables column too. The job that's compressing your margin is also the one you're waiting 70 days to collect on. That's two problems, not one, and your blended gross margin shows you neither. Your days sales outstanding by job type is worth knowing. This is how you start building it.


FAQ

If my accountant gives me a P&L every month, why isn't that enough to catch job-level losses?

A standard P&L organizes costs by category across the whole business. It can tell you that labor expense was $47,000 last month. It cannot tell you whether that labor was generating 45% gross margin on service calls and 19% on installs. That distinction requires costs assigned to jobs or job types — a different structure than the general ledger your accountant maintains. The accountant's P&L is built for tax compliance and financial reporting. It's the wrong tool for operational diagnosis, and asking your accountant to fix this is asking for the wrong thing. What you need is job-level cost tracking, which you control.

How do I allocate overhead to individual jobs without a full accounting system?

Total your monthly fixed overhead and divide by your total billable hours for the month. That's your overhead rate per billable hour. Multiply by hours on each job. You're not capturing every nuance of cost behavior, but you're getting overhead into the job cost rather than leaving it floating as an unallocated lump. Once you've run this for a few months and trust that the inputs are right, you can refine the method. Start there.

Which service line should I job-cost first if I can only start with one?

Start with the line you're least certain about. The service line that feels like your best performer without clear supporting data is exactly where surprises tend to live. In my experience with shops under 25 trucks, installs are the most common source of hidden margin loss — the cost structure is more complex, and the equipment cost increases from SEER2 and refrigerant transitions moved faster than pricing did in most shops.

What's the right gross margin target per job type?

I'll push back on the benchmark framing. The right floor for each service line depends on your overhead rate, your burden rate, and your local competitive pricing — not an industry average. What matters more than a benchmark is knowing your own floor margin per job type, pricing above it with intent, and tracking whether you're hitting it. I've seen shops with lean fixed overhead sustain install margins that would look dangerously thin for a shop carrying a larger facility and full admin staff. Get your own numbers right before you compare them to anyone else's.

My jobs vary too much in size and scope — can job costing even work for a shop like mine?

The variation is an argument for job costing, not against it. If your jobs vary widely in size, your blended margin is averaging across a wider distribution. The distortion is larger, not smaller. Start by grouping similar jobs — standard equipment replacements, service calls, diagnostic-only calls, large renovation installs — and run the cost sheet by group. You'll get most of the insight with a fraction of the data entry, and you'll see quickly which groups are structurally different enough to track separately.

At what point does it make sense to use software for job costing instead of a spreadsheet?

When the manual process takes more than two hours a week to maintain and you're confident the inputs are correct. Most shops I work with run a spreadsheet for the first several months — long enough to get the burden rate, truck cost, and overhead allocation numbers dialed in — then move the structure into their field management software once they know what they're asking it to track. The sequence matters. If you build the software layer before you understand the inputs, you'll end up with expensive reports built on bad assumptions, and job costing still won't be happening.

Enjoyed this article?

Get articles like this in your inbox every Monday. Free, no spam.

More from The Backcharge