Job Costing in Construction Accounting: A Practical Guide
Job costing in Construction Accounting is the process of assigning every dollar a construction job spends to that specific job, then comparing those costs against the job’s budget at the cost-code level. The profit on a job isn’t decided the day the final invoice goes out. It’s decided earlier, by the daily discipline of tracking, coding, and reviewing costs while the work is still happening.
Here’s the thing nobody selling job cost software will tell you: the software already does job costing correctly. Every platform on the market can add a column and run a report.
The problem is what happens before the system ever sees the number: the coding decision, the timing, and the handoff from the field to the office. That’s a people-and-process problem, and a report is only ever as good as the coding decision somebody made three weeks ago at 6pm.
What Job Costing in Construction Actually Tracks

A job cost system has to cleanly track four direct cost types, plus a fair allocation of indirect costs and overhead.
Labor is the wage plus the burden, payroll taxes, workers’ comp, benefits, and every other cost that rides along with an hour worked. If you report only the base wage, you’re understating true labor cost, and that gap compounds fast with a large crew.
Materials include everything purchased specifically for the job, including the small consumable items that are easy to leave uncoded. One distinction worth getting right: materials delivered to site but not yet installed aren’t progress. Coding them into costs-to-date the moment they arrive inflates the job’s apparent progress.
Most contractors’ systems hold uninstalled materials out of the cost-to-cost measure until they’re actually installed, which is the cleaner default. (Where the owner takes control of a significant third-party-supplied item well before it is installed — elevators, switchgear, a generator — ASC 606 has a specific treatment: the cost comes out of the progress calculation, and revenue on that item is recognized at cost, with no margin.)
Subcontract costs are payments to trade partners, plus any retainage still held back.
Equipment covers owned equipment charged at an internal rate and rented equipment billed directly to the job.
Beyond those four, indirect costs and overhead need a fair, consistent allocation method. Skipping that step, or doing it inconsistently from job to job, is one of the most common reasons a job looks more profitable on paper than it actually is.
None of this works without cost codes. Most contractors build their code structure around the CSI MasterFormat divisions, so the field, the project managers and accounting are all speaking the same language.
In practice you will find both versions in use: MasterFormat moved to a 50-division structure in 2004, but a great many contractors are still running the legacy 16-division numbering their system was set up with a decade or more ago, and there is nothing wrong with that as long as everyone is on the same one.
A contractor doing foundations on the legacy structure might use 03-300 for cast-in-place concrete, then break that down into 03-300-L for labor, 03-300-M for materials and 03-300-E for equipment. On the current structure the same work sits under 03 30 00.
A job is only as granular as its code structure, and a code structure nobody in the field understands produces clean-looking garbage. Everyone can point to the total. Nobody can tell you which piece of it is real.
Job Costing vs WIP: Where One Ends and the Other Begins
Job costing tracks actual costs against budget for a single job at cost-code level. A work in progress schedule takes that same job cost data and adds revenue recognition, comparing what’s been earned against what’s been billed across every active job at once.
Job costing is the input. WIP is the report built from it, and good WIP is impossible without good job costing underneath it.
The industry still calls this “percentage of completion” out loud, every day, including CPAs, and using the phrase isn’t wrong. What’s wrong is writing as though it’s still a standalone method with no standard behind it.
Under ASC 606 (ASC 606-10-25-27 on over-time recognition, with input and output methods addressed at 606-10-55-16 through 55-21), a construction contract typically recognizes revenue as the work progresses, measured using either an input or output method, cost-to-cost being the input method almost every contractor actually uses.
For more on how that revenue-recognition side works, see our companion piece on work in progress accounting.
Committed Cost vs. Actual Cost vs. Cost-to-Complete
These three numbers sound similar, but they answer three different questions, and mixing them up is one of the fastest ways for a job cost report to mislead everyone who reads it.
Actual cost is money already spent and posted, paid invoices, processed payroll, and it’s the easiest number to over-trust because it only shows what’s happened, not what’s still coming.
Committed cost is money the company must spend even before it’s invoiced, like open purchase orders and unbilled subcontract balances. A signed $80,000 subcontract is a real obligation the moment it’s signed, not when the invoice arrives.
Cost-to-complete is the estimated cost of finishing the remaining work, based on current site conditions, not the original bid. It’s also the one most likely to go stale, since a busy project manager often defers the honest update, especially when the original bid numbers still look good on paper.
A Worked Example: Where the Top Line Lies
Here’s where job costing earns its keep. A job can look perfectly healthy at the total budget level while one specific cost code is quietly bleeding, and the only way to catch it is by looking at the codes, not the total.
Take a $700,000 job with roughly two-thirds of the cost already incurred:
| Cost Code | Budget | Actual to Date | Committed | Cost to Complete (uncommitted) | Projected Total | Variance |
| 03-300 Concrete | $180,000 | $150,000 | $10,000 | $65,000 | $225,000 | +$45,000 over |
| 02-200 Sitework | $220,000 | $140,000 | $5,000 | $40,000 | $185,000 | -$35,000 under |
| 16-000 Electrical | $150,000 | $90,000 | $20,000 | $30,000 | $140,000 | -$10,000 under |
| 01-000 General Conditions | $150,000 | $100,000 | $0 | $50,000 | $150,000 | $0 |
| Total | $700,000 | $480,000 | $35,000 | $185,000 | $700,000 | $0 |
Look at the total row and the job appears to be sitting exactly on budget. It isn’t. Concrete is running $45,000 over, quietly absorbed by underruns in sitework and electrical, two codes that have nothing to do with why concrete is bleeding.
A report that only shows the total told the project manager everything was fine. The cost-code breakdown says otherwise, and it’s the only version of this report a project manager should actually be reading.
One convention note, because reports differ: in this table cost-to-complete covers only the remaining work that is not yet committed, so the three cost columns add to the projected total.
Plenty of job cost reports fold committed cost into cost-to-complete instead. Neither is wrong, but adding the columns on the wrong assumption double-counts, so check which one your report uses before you do arithmetic on it.
Where Job Costs Actually Go Wrong
Four problems account for most of the damage we see in job cost reports. Each one is also a place where a platform’s mechanics either catch the gap early, or let it grow unnoticed until it’s expensive.
Change Orders Worked Before They’re Entered
A change gets a verbal yes on site. The crew starts the extra work, materials get ordered, hours start piling up. The change order itself doesn’t get entered for weeks, sometimes never.
Costs post against a budget that doesn’t reflect the added scope, so the job cost report shows an overrun that isn’t really an overrun, and the contract value never moved to reflect the extra work either. On a first close for a new contractor client, we typically find 20–25% of change orders approved in the field and never entered in the accounting system.
The check that finds it is not a report. It is reading the coded invoices against the commitments: every cost sitting on a job needs an approved change order or an original budget line behind it, and the ones with neither are the change orders nobody entered.
There is a second version of this that is more common and more expensive. The owner directs the change, the crew builds it, and the price is never agreed. That is still an approved modification the moment work starts, so the costs are landing on the job whether or not anyone has signed a number.
On a job cost report the tell is a cost code with actuals climbing steadily against a budget line that has not moved in weeks. The number worth watching is not how large the unpriced balance is, it is how old it is. A change order sitting unpriced for four weeks is a negotiation in progress. The same one at six months is a write-off nobody has booked yet. Unpriced amounts belong in their own column, never folded into the budget, because the moment they are folded in nobody can see the age any more.
In Sage 300 CRE, change orders run through a structured process inside Job Cost or Project Management, tied directly to the job’s contract, commitments, and budget. Once entered, the change order updates those figures in the same place where costs are already being tracked, and approval routing can be set so that smaller changes are signed off by a project manager while larger ones are routed to finance.
We handle exactly this kind of AP coding and run vendor statement reconciliations for a Canadian commercial construction group, running their monthly accounting and progress billing directly inside Sage 300 CRE.
In Yardi Voyager’s Construction Manager module, budgets, commitments, and change orders sit inside one linked structure, and job cost updates the general ledger as transactions post. The same module handles progress billing in both directions, billing the owner on one side and paying subcontractors on the other, along with intercompany transactions where a job spans more than one legal entity.
A change order that hasn’t made it into the system yet tends to surface as a variance in cost-to-complete and projected-exposure reporting, rather than staying invisible until the job wraps up.
Costs Coded to the Wrong Job Number
Two numbering schemes exist on most jobsites, whatever number the field crew is using on their paperwork, and whatever number accounting actually opened the job under in the system. When those two don’t match, costs post to the wrong job, or to no job at all, and nobody owns the reconciliation between the two.
What we do at the first close is pull the field’s job list and the accounting job list side by side and reconcile them as two documents, because nobody on either side owns that reconciliation and it never happens on its own.
In Sage 300 CRE, a job has to exist in Job Cost before a cost can be coded to it, forcing a numbering mismatch to surface as a rejected entry rather than a silent misfile, provided someone actually reviews the exceptions queue instead of just clearing it.
In Yardi Voyager’s Construction Manager, the linked job structure makes an orphaned or misnumbered cost easier to spot in a variance report, since it either hits the wrong job’s budget or fails to tie to any open job at all.
Labor Burden Left Out
Some jobs get charged the full cost of labor, wage plus burden. Others only carry the base wage, with payroll taxes, insurance, and benefits sitting in overhead instead. Once that inconsistency creeps in, comparing profitability from one job to the next stops meaning much, and the error scales directly with headcount, the bigger the crew, the bigger the gap.
The quickest way to find it is to divide total labor cost by total labor hours for each job and put the results next to each other. Jobs carrying burden and jobs carrying only base wage separate immediately, and the gap tells you which is which.
Both Sage 300 CRE and Yardi Voyager’s Construction Manager support burden calculation as part of their payroll-to-job-cost integration, though the exact configuration varies and is worth confirming directly with whoever manages your platform before relying on it.
Equipment Time Never Charged to a Job
Owned equipment sitting on-site, along with shop overhead and supervision, often stays parked in company overhead instead of getting allocated to the jobs actually using it. The equipment looks free, and the job using it looks more efficient than it really is, quietly masking thin margins on the next bid.
We compare total equipment cost in the general ledger against total equipment cost posted to jobs for the same period. The difference is the equipment nobody charged out, and on the first close, it is rarely small.
In Sage 300 CRE, the Equipment Cost module tracks ownership, maintenance, and usage for every piece of equipment in the fleet. Internal rate tables post usage charges to the jobs that used the equipment, and that same cost and revenue data flows into Job Cost, the general ledger, and Billing.
In Yardi Voyager’s Construction Manager, equipment and indirect costs get coded to jobs and cost categories as part of normal processing, and budget-versus-actual reporting makes it visible when a meaningful chunk of cost is sitting outside the job structure entirely.
What Good Job Costing Discipline Looks Like Monthly
This isn’t a setup problem you solve once. It’s a control someone has to run every single month, on purpose.
A workable cadence: costs get coded the same day they’re incurred, not batched for end of month. Change orders move from field to accounting within days, not whenever someone remembers.
Cost-to-complete estimates get re-forecast every period based on current site conditions, not the original bid, since a stale estimate is one of the fastest ways for a job to look healthier than it is. Across the contractor books we take on, cost-to-complete estimates are stale on more than a third of active jobs at the first close we run.
Somebody specific owns each handoff. The field reports what happened. The office codes it correctly and on time. Someone reviews the cost-code detail, not just the total, weekly or biweekly, so a problem gets caught while there’s still time to fix it, not discovered at the next monthly close when the budget is already gone.
Frequently Asked Questions
What’s the difference between job costing and a WIP schedule?
Job costing tracks actual costs against budget for a single job at the cost-code level. WIP adds revenue recognition on top, comparing earned revenue against billed amounts across every active job. Job costing is the input; WIP is the report built from it.
How often should a job cost report actually get reviewed?
Weekly or biweekly, at the cost-code level, not just the total. A monthly cadence usually means the budget’s already gone by the time a problem surfaces.
What’s the real difference between committed cost and actual cost?
Actual cost is money spent and posted, paid invoices, processed payroll. Committed cost is money the company is obligated to spend but hasn’t been invoiced yet, open purchase orders and unbilled subcontract balances. A report showing only actual cost hides exposure that’s already locked in.
Why does labor burden matter so much in job costing?
The base wage alone understates the true cost of labor. Leaving out payroll tax, workers’ comp, and benefits, or applying them inconsistently across jobs, makes job-to-job profitability comparisons meaningless.
Can a job look profitable and still be losing money in one area?
Yes, and it’s one of the most common ways job costing gets misread. A job’s total budget can sit right on target while a single cost code runs significantly over, masked by underruns elsewhere that have nothing to do with the actual problem.
Does better software fix inconsistent job costing on its own?
No. Every major platform can calculate a job cost report correctly once the data is in it. The failure almost always happens before that, in the coding decision made in the field or the timing of when a change order gets entered.
The Bottom Line
Job costing isn’t a hard concept. Staying consistent with it is the actual challenge: coding every cost correctly the first time, updating cost-to-complete estimates with what’s really happening on-site instead of what the original bid assumed, and reviewing the report often enough to catch a problem while there’s still time to fix it.
If your job cost reports feel incomplete, delayed, or hard to trust, the fix is usually construction accounting services built around a clean cost code structure and a real review rhythm, not a new spreadsheet template. Whether your books run on Sage 300 CRE, Yardi, QuickBooks, or something else, that’s where we work, building job costing inside the platform you already use.
Book a free consultation and we’ll walk through how your current job costing setup compares to where it should be.
