Your Gross Margin Is an Average — And Averages Lie
Your Gross Margin Is an Average — And Averages Lie
In 2019, I sat across from the owner of a 14-truck residential HVAC shop in the mid-Atlantic, going through his P&L as part of an acquisition analysis for Atlantic Comfort Partners. He was a good operator. Trucks were clean, callbacks were low, his dispatcher ran the service department without much intervention from him. His blended gross margin was sitting at 38%, which is respectable for residential HVAC. He was proud of it. He should have been — it took real discipline to hold that number.
The problem was that 38% was a fiction. Not because he'd cooked the books. Because it was an average, and the average was lying to him.
What Your Blended Gross Margin Is Actually Telling You (Hint: Not Much)
Your gross margin percentage on the P&L is a weighted average of every job type you ran during the period, with the weights hidden inside the revenue mix. If you did $600,000 in service and repair and $400,000 in new installs, your blended margin reflects both — but it doesn't tell you which category is pulling the number up and which is dragging it down. Most P&Ls aren't built to show that.
This is the structural problem. A single gross margin percentage is not a diagnostic tool. It's a summary statistic, and summary statistics conceal variation by design.
The confusion gets worse because most small contractors mix up markup and margin. Markup is what you add to cost. Margin is what's left of revenue after cost. A 50% markup on a $1,000 part gets you $1,500 in revenue and a 33% gross margin — not 50%. When you price a job at "50% markup" and read the resulting margin as "50%," your cost-of-doing-business math is already off before you get to the job-type question.
A blended gross margin tells you that the business is profitable on average. It does not tell you which parts of the business are keeping it that way, or which parts are quietly eating the gains.
The 2019 shop was the clearest version of this I've encountered. The diagnostic and repair tickets were running healthy margins. The install margin was not. Because installs were the smaller revenue line, their damage was absorbed into the blend without registering as a problem. The owner had been losing money on every install for three years and didn't know it, because the number he used to measure performance was structurally incapable of showing him that.
The Job Category That's Quietly Keeping the Lights On
In most residential shops under 25 trucks I've worked with, one job category is carrying the others. Diagnostic and repair service calls are the most common load-bearing line. The tech diagnoses, the customer pays, the job closes the same day. Labor hours are predictable. Parts cost variability is low. Cash conversion is fast.
Install work has the opposite profile. Equipment cost is high and volatile. Labor hours are harder to estimate — especially when the job runs into an attic that wasn't what the photos suggested or a lineset that needs rerouting. Job completion may be same-day but final billing sometimes lags. And in shops that also carry slow-paying commercial maintenance accounts, the cash timing gets genuinely painful.
The subsidizing job type is usually also the fastest cash converter. The subsidized job types tend to be the slowest. That's a structural feature of how residential HVAC revenue works, not a coincidence — and it means the owner feels solvent right up until install volume grows enough to break the blend.
At Atlantic Comfort Partners, our analysts knew to look for this pattern early in any acquisition. The shops that came to market at a discount were often the ones where we found the subsidization before the owner did. Not because those owners were unsophisticated — because nobody had ever shown them the job-type breakdown. They were running their business on a P&L designed for tax reporting, which is not the same thing as a P&L designed for operational decisions.
Why the Flat-Rate Book Doesn't Fix This
The industry's standard answer to margin problems is a flat-rate pricing system. Here's what it actually buys you.
Flat-rate books from the major vendors give you predictable revenue per ticket. The tech arrives, the customer chooses from a menu, the price is fixed, the invoice is clean. That's genuinely useful for customer experience and for eliminating the technician's temptation to under-quote on the driveway.
What it does not give you is margin visibility by job type. The price book is built on cost assumptions that may or may not reflect your actual numbers — your burdened labor rate, your vehicle operating cost per hour, your overhead allocation. The major vendor books are calibrated for average shops. Average shops don't exist. They produce a price that covers costs for a shop that looks like the median shop in their customer base, which may or may not be you.
The SEER2 transition is a live example. When equipment costs moved in 2023, shops using flat-rate books faced a specific problem: the book's price already had an equipment cost assumption baked into the line item, and that assumption was no longer current. The shops that caught it updated their books. In my experience, more didn't than did — and those shops absorbed the equipment cost increase without passing it through, because the flat-rate price felt current even when the cost underneath it had moved.
The deeper issue is that price book line items don't map cleanly to job-type cost categories. A flat-rate book tells you what to charge for a TXV replacement. It does not tell you what your install division's gross margin is relative to your service division's. The opacity that lives in a blended P&L does not disappear when you add a flat-rate book. It just moves.
What the P&L Looked Like When We Finally Broke It Out
Back to the 2019 shop. When I disaggregated the blended 38% gross margin into job categories, three numbers came out of the analysis.
Service and repair: approximately 51% gross margin. Strong. The labor was efficient, the parts markup was holding, and the technicians were closing diagnostic calls at a good rate.
Maintenance agreements: approximately 34%. Acceptable, though the agreements were priced in a way that front-loaded the customer acquisition cost and didn't account well for aging equipment generating more callbacks than the agreement fee could absorb.
New installs: approximately 19%. And had been for three years.
He went quiet when I showed him the install number. Not defensive. Quiet. Because he immediately understood what it meant. He'd been growing his install volume intentionally — running sales promotions, buying leads — because he thought he was building the more scalable part of the business. What he'd actually been doing was running an increasingly efficient machine for generating losses, subsidized by the service department he'd been treating as the lower-status revenue line.
The install pricing wasn't reckless. His equipment costs were market rate. His labor hours were estimated in good faith. The problem was overhead allocation. He was allocating overhead evenly across revenue dollars rather than by job type. Installs consumed a disproportionate share of his warehouse space, his project coordinator's time, and his warranty callback hours — but they were being charged overhead at the same rate as a two-hour service call. The install P&L looked better than it was. By a lot.
The Spreadsheet You Need to Pull This Week
You don't need new software. You need five columns and 90 days of job data.
The layout: job category, total revenue, total direct labor cost, total direct materials and equipment cost, gross margin dollars, gross margin percentage. One row per job category. For most residential HVAC shops, the categories are service and repair, new installs, maintenance agreements, and other (duct work, IAQ add-ons, anything that doesn't fit cleanly).
The inputs are sitting in whatever system you're already using. If you're on a field service platform, the closed job export will have what you need, though you may have to do some configuration to get costs in a usable format. Paper-based shops have invoices with parts costs and timesheets with labor hours — the data exists, it's just unassembled.
One definition worth having clearly before you run this. Contribution margin is not the same as gross margin. Gross margin deducts direct costs and may include a fixed overhead allocation. Contribution margin deducts only the variable costs a specific job actually consumed — the labor hours, the materials and equipment — and leaves fixed overhead out. Contribution margin is the number you want when you're asking whether to do more of a job type or less. For this spreadsheet, start with gross margin per category. That's the cleaner starting point and uses data you can pull without debating overhead allocation methodology. Once you see the gross margin spread across categories, the overhead question becomes obvious on its own.
What to Do Monday Morning
Pull the last 90 days of closed jobs from your system. Sort by job type. If your software won't do that, run a manual sample — 20 closed jobs per category is enough to see the pattern. For each category, total the revenue and total the direct costs: labor at burdened rate, parts and equipment at actual cost. Calculate gross margin per category.
Then look at the spread.
If your service and repair is running well above your installs, don't raise install prices yet. First, run a cost-of-doing-business calculation specific to installs. The overhead allocation is almost always wrong before the price is — installs consume more overhead than a revenue-proportional allocation gives them credit for, and fixing the allocation changes the target price without you having to guess at a number.
If the allocation math confirms the price is genuinely too low, then raise it. Know which problem you're solving before you solve it.
The 2019 shop owner raised his install prices after we rebuilt the cost model. He restructured the maintenance agreements. He left the service department alone, because it didn't need work. He had a business that made money on every category — not just the one that had been quietly holding the whole thing together.
FAQ
My accountant gives me a P&L every month — why isn't that enough to see this problem?
A standard P&L is organized for tax reporting and financial compliance, not operational decisions. It shows you revenue, cost of goods sold, and gross margin for the business as a whole. Unless your accountant is also doing job-type breakdowns — which requires your job costing data, not just your QuickBooks chart of accounts — the P&L can't show you which categories are profitable. Most accountants serving small shops aren't doing that segmentation unless you ask for it specifically and give them the underlying data to work with.
How do I categorize a job that's part service call and part install, like a repair that turned into a system replacement?
Split it at the invoice level if you can. If the diagnostic fee and repair labor were on a separate line before the customer decided to replace, treat the first part as service and repair and the system replacement as an install. If it was quoted as a single job from the start, it goes in installs. A diagnosis-to-replacement job has a different cost profile than a planned installation, and mixing them into the install category will distort both.
What gross margin percentage should I be hitting by job type?
I'll give you what I've seen across the shops I've worked with, with the caveat that your local labor cost and overhead structure will move these numbers. Service and repair tends to clear 45-55% in most markets I've audited. New installs run tighter — a well-run shop with accurate overhead allocation is typically in the 30-40% range, and hitting the high end requires real discipline on equipment cost and labor hour estimating. Maintenance agreements vary most widely based on how they're structured; agreements priced without accounting for callback and warranty labor on aging equipment tend to fall below 30%, sometimes well below. If yours are, that's usually the first place to look.
I use a field service platform with job costing reports built in — am I already doing this?
Maybe. The report being available and the report being accurate are not the same thing. Job costing reports require that your technicians are logging time against jobs accurately, that your price book costs are current (if equipment cost in your price book is stale post-SEER2, the margin calculation is stale), and that job types are tagged consistently. Pull the job costing report for the last 90 days, filter by job type, and check whether the cost columns reflect actual cost or placeholder figures.
If my install margin is low, is the problem my pricing, my equipment cost, or my labor cost?
Look at the three components separately on a sample of 10 recent installs. Calculate equipment cost as a percentage of total job revenue, direct labor hours times burdened rate as a percentage of job revenue, and what's left. If equipment is running above 45% of revenue, that's your equipment cost problem — either the markup is too low or equipment is being sold near cost as a competitive tactic. If labor is the culprit, check whether estimated hours matched actual hours; a consistent gap means your estimating assumptions are wrong, not your rate. If both look reasonable and margin is still thin, the issue is overhead allocation.
How often should I run this analysis once I set it up?
Quarterly is the minimum that's actually useful. Monthly is better if your revenue mix shifts seasonally — which in residential HVAC it does, because install volume follows equipment sales cycles and service call volume spikes with weather. The point is to catch a category drifting before it drifts far enough to damage the blend. Pull the same five-column spreadsheet each quarter and compare it to the prior quarter. A meaningful drop in a single category's margin is worth investigating before it compounds.
Enjoyed this article?
Get articles like this in your inbox every Monday. Free, no spam.
