Your job profit number is almost certainly not wrong because QuickBooks is broken. It is wrong because a cost that exists in your books never arrived at the job, and QuickBooks reported the number it had without telling you what was missing. That is why the fix is a diagnosis rather than a setting.
One exception is worth knowing first, because it makes honest people think the software is lying to them. In QuickBooks Online, labor can appear on your project detail page and be absent from your Project Profitability report at the same time, and both screens are behaving as designed. Once you know why, seven other causes fall out of the same logic.
The short answer
QuickBooks tracks job profitability by reading transactions that carry a project tag and hit an income or expense account. Anything failing either test is invisible to the report. It is not dropped, not flagged, and not counted. It sits in your P&L making the company look fine while your job margins look better than they are.
So the diagnosis is always the same shape. Find the total that is missing, then find which of the eight paths it took to get lost. Do not start by changing settings, and do not start by shopping for software. Both are how contractors end up with two sets of numbers instead of one correct one.
Run this test first, it takes 15 minutes
Open Reports and run Profit and Loss by Customer for the last full month. QuickBooks Online adds a column called Not Specified, which holds every transaction carrying no customer or project. That column answers the only question that matters right now: how much cost is missing, in dollars.
Then do the second half. Add up total cost across all active projects for the same period and compare it to direct costs on your P&L. The gap should be small and explainable. If P&L direct costs are 180,000 dollars and your projects total 120,000 dollars, you have 60,000 dollars of job cost sitting on no job, and no amount of reading the profitability report will show you that.
Tip
Do this on a closed month, not the current one. Half of what looks like a reporting failure this month is a bill you have not entered yet. Late bills are a timing problem, not an allocation problem, and mixing the two wastes an afternoon.
Now work the causes below, ordered by how much money they usually account for at a small contractor rather than by how easy they are to fix.
Cause 1: your payroll is one line, so no job has any labor on it
This is the single largest hole, and it is close to universal among contractors running payroll through Gusto, ADP, Paychex or similar rather than QuickBooks Online Payroll. The provider sends over a journal entry with one line for total wages. One line cannot be tagged to six projects, so it is tagged to nothing, and every job in your file shows materials and subs with no labor at all.
The fix is not software. On the payroll journal entry, replace the single wages line with one line per project, all posting to the same wages account, each tagged to its project. An operator on r/QuickBooks working through this described the result plainly: "I can create multiple rows that all fall under the salaries line item, but classify each one to an individual project. When I tried it this morning it did apply the amount we paid in wages to the specific project."
A bookkeeper in the same thread confirmed it is standard practice: "You can definitely have a Journal Entry that reclass payroll labor to the appropriate project, I do this all the time for construction clients. Seeing Gross Margin after Direct Costs AND Labor is critical to running a business, if your accountant can't do that I would possibly look for a better one."
Before you hope the payroll integration handles it, check. As another commenter noted, plenty of third-party payroll systems now have job tracking that syncs to QuickBooks, but the sync is usually at the customer level rather than the project level. Customer level means the cost reaches the client, not the job, which on a repeat client with four jobs a year is the same as reaching nothing.
Cause 2: hourly cost rates, the two screens that disagree by design
If you do not run QuickBooks Online Payroll, QuickBooks offers hourly cost rates instead: a per-employee cost rate set on the Projects dashboard, multiplied by tracked hours. It works, it appears immediately, and it is the reason a lot of contractors think their file is corrupted.
Writing on Intuit's own Firm of the Future publication, Heather Satterley spells out the behavior: "If the hourly cost rate is used, you'll see labor costs calculated on the Project detail page, but it won't appear on the Project Profitability Report since the hourly rate cost calculation isn't recorded as a transaction on the books."
Read that twice. The labor figure on your project detail page is a calculation. The Project Profitability report reads transactions. A calculation is not a transaction, so the report cannot see it. No support agent is going to fix this, because there is nothing to fix. The labor is real and it lives in a separate report, Time Cost by Employee or Vendor, which you run and reconcile by hand.
Watch out
The same article confirms the other half: with QuickBooks Online Payroll enabled, QuickBooks assigns the weighted dollar amount of each paycheck to projects based on hours worked, including wages and payroll taxes, and that cost does appear on both screens. So the labor question is really a payroll question. Where your payroll runs decides whether your job profit is readable.
Cause 3: the owner is on the tools and takes draws
At a two to eight person contractor, the owner is often the most productive person on site. If that owner is paid through draws rather than payroll, their hours cost nothing in QuickBooks. Draws are equity, not expense, so they never touch a job.
The consequence is worse than a missing number. It is a systematically inverted one. The jobs where you personally did the most work are the jobs that look the most profitable, which means your own labor is quietly subsidising your bids on exactly the work you are most likely to sell more of.
A contractor's bookkeeper raised this on r/Bookkeeping in almost those words: "I really just want a way to track the owners hours and expense to the jobs to see what the profitability would be if the owner was paid like an hourly employee." The workaround that thread converged on is the only one that puts the cost where the report can read it:
- Create a service item called something like Owner Field Hours, tick the box for "I purchase this product/service from a vendor" so the item carries an expense account, and map it to an expense account such as Owner Job Cost Allocation.
- Set the purchase rate to what you would pay an employee to do that work, not what you take home.
- Set yourself up as a vendor, log hours to projects on a weekly timesheet, then enter a weekly bill using that service item with the hours per project.
- Optionally offset it with a journal entry debiting the allocation account and crediting owner draws, so the P&L is not distorted while the job still carries the cost.
The lighter version, if you do not want a shadow expense account in your books, is to log the hours as non-billable time against each project and apply a rate in a spreadsheet at month end. Clunkier, and the contractor in that thread said so, but it answers the question.
Most of these causes are one problem wearing different hats: where work is recorded and where money is recorded are two systems, and a human is expected to keep them agreeing. A custom CRM built around your job flow hands accounting a clean allocation instead of a weekly reconstruction.
Cause 4: it is tagged to the customer, not the project
QuickBooks Online will happily let you put a bill against a parent customer while the project sits underneath as a child record. The transaction looks assigned. It shows on the customer. It does not show on the project, because the project is a different record.
Check this when the missing amount is oddly specific: one subcontractor, one supplier, one recurring charge. Open the transaction and read the Customer or Project column line by line. On a multi-line bill the tag lives on each line, not the header, so one untagged line in five quietly disappears while the other four report correctly.
A related trap is duplicate job records. Toran Accounting, which works with construction clients, flags this as a QuickBooks Online specific failure: it is easy to create a second sub-customer with a near-identical name for the same job, and every report then splits across the two with nothing flagging the discrepancy. "Henderson Kitchen" and "Henderson Kitchen Reno" each show half a job and neither looks like a problem.
Cause 5: it is coded to an account the report does not read
A cost has to hit an income or expense account to appear in job profitability. Two coding mistakes break that.
The first is a cost posted to a balance sheet account. A material purchase coded to an asset account, or a subcontractor payment applied against a liability, will never appear on a profitability report no matter how correctly it is tagged. When a contractor on r/QuickBooks could not find his costs on project reports despite tagging them, another commenter asked the question that usually cracks it: are the accounts on the line items expense accounts rather than balance sheet accounts?
The second is about where the cost lands. In another r/QuickBooks thread a contractor found a 1,500 dollar bill missing from a project total that should have read 3,774 dollars and read 2,274 dollars. The bill was tagged, and the category was "Contractors". The answer he got: "Are you looking for them to show up above gross profit? If so, you'll need to classify as Cost of Goods-Labor."
That is the chart of accounts talking. Direct job costs belong in cost of goods sold. General expense categories sit below gross profit, so the cost is in your books, in your P&L, and in the wrong half of the report you are reading. If your subcontractor spend sits in an operating expense account, your gross margin per job is fiction and so is your company gross margin.
Cause 6: the transaction existed before the project did
QuickBooks Online expects the project to be chosen when a transaction is created. Moving an existing invoice into a project afterward, particularly a paid or partially paid one, is where contractors hit a wall. One operator described the outcome on r/QuickBooks: they could not do it, were given a bad solution by support, and ended up redoing all of 2024's invoices before abandoning Projects entirely.
The rule: create the project before the first estimate, invoice, bill or timesheet touches it. It costs 30 seconds at the start of a job and is not recoverable later. Our step by step setup walkthrough covers the other setup steps that share this property, because four of them are not retroactive either.
Cause 7: one vendor bill covers three jobs
Your electrician spends the morning at one address and the afternoon at another, then sends one invoice. Your supplier bills monthly across every job you bought for. QuickBooks can split those across projects at the line level, but only if the bill arrives with enough detail to split.
Two answers work. Require one bill per job from subs and suppliers, enforced through your AP process, on the reasoning one operator gave bluntly in an r/quickbooksonline thread: they want to get paid, believe me. Or accept consolidated bills and make the project manager, not the bookkeeper, mark which cost belongs to which job before it reaches accounting. What fails is letting the bookkeeper guess, because the bookkeeper was not on site. A developer in that thread who has built custom reporting on QuickBooks Online added the caveat: the reports do not map well at the line level, and pulling line-level project detail out of bills took custom work.
Cause 8: the number is finally correct, and it is still not your profit
Suppose you fix all seven. Your Project Profitability report is now accurate. It is still gross margin on direct cost, and treating it as profit is how contractors end a strong year with a thin bank account.
Two categories are missing. The first is labor burden. QuickBooks Online Payroll puts wages and payroll taxes on the job. It does not put workers compensation, benefits, paid leave or safety training there. Toran Accounting puts typical burden at 25 to 40 percent of direct labor depending on state and benefit structure, so a job showing 40,000 dollars of labor may have cost closer to 53,000 dollars.
The second is overhead. Shop rent, office staff, software, fleet insurance and general supervision never touch a job in QuickBooks. Edgestrat Finance, which does contractor accounting, sizes it with an example: a project manager on 95,000 dollars a year splitting time across six jobs makes all six look better than they are if none of that time is allocated. Their simplest recovery method divides annual overhead by annual revenue. On 150,000 dollars of overhead against 1,000,000 dollars of revenue, that is 15 percent every estimate must carry just to break even, before any profit at all.
By the numbers
Toran Accounting's full job cost formula has six components: direct labor, labor burden, materials, subcontractor costs, equipment allocation and allocated overhead. Their worked framing job comes to 154,330 dollars total: 40,000 dollars labor, 12,800 dollars burden at 32 percent, 65,000 dollars materials, 18,000 dollars subs, 4,500 dollars equipment and 14,030 dollars overhead at 10 percent of direct cost. QuickBooks Projects, configured perfectly, reports three of those six.
What Projects sees, and what it never will
| Cost element | On the Project Profitability report? |
|---|---|
| Materials and subcontractor bills | Yes, if tagged to the project and coded to an expense or COGS account |
| Wages via QuickBooks Online Payroll | Yes, weighted by hours per project, wages and payroll taxes only |
| Labor via hourly cost rates | No. Project detail page only |
| Owner hours paid as draws | No. Never, without a workaround |
| Workers comp, benefits, paid leave | No |
| Equipment ownership cost | No, unless you invoice yourself an internal rate |
| Office rent, admin salary, software | No |
| Retainage held back | Not separately. It hides inside receivables |
| Committed costs on open POs | No |
That table is not a list of QuickBooks failures. It is a scope statement. Projects answers one question well: did the direct costs you recorded against a job beat the revenue you recorded against it. Every row marked No is a question you answer somewhere else, on purpose.
The Friday routine that keeps it honest
Fifteen minutes weekly beats three hours at year end, because a cost you can still remember is a cost you can still allocate correctly.
- Run Profit and Loss by Customer for the week and read the Not Specified column. If it is not near zero, allocate what is in it before Monday.
- Confirm this week's payroll entry is split by project rather than sitting on one line.
- Check that every project opened this week existed before its first transaction.
- Open any bill over your threshold and confirm the project tag is on each line, not just the header.
- Compare cost to date against budget on the two largest active jobs. This is the only step that changes an outcome rather than a number.
Protect step five when the week gets away from you. A cost report read after the job closed is a history lesson. One read on Friday of week two is a conversation with the client while there is still a job to talk about.
When to stop patching QuickBooks and change the system
Fix the inputs first. Seven of the eight causes are data entry paths, and none are solved by buying software. A contractor who buys a job costing add-on to fix an unsplit payroll journal entry ends up with an unsplit payroll journal entry and a subscription.
The threshold to move is not revenue, it is labor. When someone spends a recurring block of hours every week reconstructing job costs, splitting entries, exporting to a sheet, chasing which of two sub-customer records a bill went to, that work has become a role, and roles cost more than tools. One operator in that r/quickbooksonline thread had already made peace with it: they now use QuickBooks essentially as a database and report elsewhere, on the grounds that the reporting has always been the weak part.
If your job costs are reassembled by hand every week, the problem is upstream of accounting. We build custom CRMs for contractors and home service businesses that capture hours, materials and subs against the job as the work happens, so job profit is a number your crew produces rather than one your bookkeeper reconstructs.
The last thing to say is the least comfortable. Every cause on this list makes jobs look more profitable than they are, never less. Missing labor, missing owner hours, missing burden, missing overhead: all push the same direction. If you have been bidding off these numbers for a year, the correction will not be a pleasant surprise, and it is still the most valuable half hour you will spend this month. For jobs that span a month end, our guide to tracking WIP in QuickBooks picks up where this one stops.