What it is
A job can be profitable on the WIP schedule and still use cash. Job cash position counts actual cash: payments received from the owner and payments made to subs, suppliers, and payroll.
It differs from over/under billing, which compares billings with earned revenue, not cash.
Why operators track it
- Working capital. Cash-negative jobs draw on the company's cash or credit line.
- Collection focus. Shows which owners to chase.
- Pay timing. Shows whether the contractor is paying subs before being paid.
- Bidding. Jobs with heavy retainage or slow owners need more working capital.
How it is calculated
Job cash position = cash received − cash paid
- Cash received = owner payments applied to the job.
- Cash paid = AP payments, payroll, and other disbursements charged to the job.
- Internal equipment and overhead allocations are not cash; leave them out or show separately.
- A projection adds expected receipts and payments by month.
Worked example
Job 2417 has received $990,000 and paid $845,000: +$145,000. Job 2420 has received $150,000 and paid $225,000: −$75,000. Job 2431 has received $1,450,000 and paid $1,560,000: −$110,000, with $170,000 of retainage still held by the owner.
How to read it
- Explain negatives. Underbilling, slow payment, retainage, and early sub payments are the usual causes.
- Compare to over/under billing. Overbilled jobs are usually cash positive; if not, collections are the issue.
- Retainage can push late-stage jobs negative until release.
- We do not publish a benchmark.
Definitional choices and common pitfalls
- Payroll. Include payroll by job from labor distribution, using amounts actually paid.
- Allocations. Exclude internal equipment charges, or show them separately.
- Timing. Use payment dates, not invoice dates.
- Projection. Actual to date only, or with a forecast. Label the forecast.
How different roles use it
| Role | How they use it |
|---|---|
| CFO / controller | Reviews cash position by job and plans the credit line. |
| Project manager | Follows up on owner payments and pay app timing. |
| Owner / CEO | Sees which jobs the company is financing. |
| Surety / lender | May review job-level cash as part of a deeper review. |
Questions it answers
- Which jobs are cash negative?
- How much is the company financing across jobs?
- Are we paying subs before we are paid?
- Which owners drive negative cash?
How to present it in a report
- One row per job: received, paid, cash position, and over/under billing beside it.
- A total across jobs.
- A monthly cumulative cash curve per job.
| Job | Received | Paid | Cash position | Over/(under) billed |
|---|---|---|---|---|
| 2431 | $1,450,000 | $1,560,000 | −$110,000 | −$134,041 |
| 2420 | $150,000 | $225,000 | −$75,000 | −$85,704 |
| 2417 | $990,000 | $845,000 | $145,000 | $73,684 |
Data you need
Fields
| Field | What it means | Example value |
|---|---|---|
| Owner payments | Receipts applied to job invoices | Oct 29, $189,000, job 2431 |
| AP payments | Checks and ACH to vendors by job | Oct 15, $82,000, Ace Electric |
| Payroll by job | Labor paid by job | Oct, $96,000, job 2431 |
| Retainage held | By the owner, and from subs | $170,000 |
| Billed to date | For comparison | $1,700,000 |
What the raw data looks like
Example data A few rows as they might come out of the source system.
| Job | Billed to date | Cash received | AP paid | Payroll paid | Cash position |
|---|---|---|---|---|---|
| 2417 | $1,100,000 | $990,000 | $612,000 | $233,000 | $145,000 |
| 2420 | $205,000 | $150,000 | $151,000 | $74,000 | −$75,000 |
| 2431 | $1,700,000 | $1,450,000 | $1,118,000 | $442,000 | −$110,000 |
Where this data usually lives
- Construction ERP and accounting holds job cost, budgets, billing, AP, and AR. For example: Sage 300 Construction and Real Estate, Viewpoint Vista (Trimble), and Foundation. Some smaller contractors use general accounting software such as QuickBooks with jobs set up as projects.
- Payroll and time tracking hold hours and labor cost by job and cost code, sometimes from a field time app.
The same field can live in more than one system. Agree with the customer which one is the source of truth.
Common data gaps and traps
- Payments not linked to jobs. AP checks pay invoices; join through the invoice to the job.
- Payroll by job. Labor distribution may post cost but not the cash date.
- Unapplied receipts. Cash received but not applied to an invoice.
- Joint checks. Owner payments made jointly to GC and sub.
Related metrics
- WIP over/under billing: billing vs earned.
- Retainage outstanding: cash held back.
- DSO and billing lag: how fast billing becomes cash.
FAQ
- Is job cash flow the same as profit?
- No. A job can show profit and still be cash negative because of retainage, slow payment, or early payments to subs.
- Should overhead be included?
- Usually not at job level. Keep it to direct job cash.
- How does it relate to overbilling?
- Overbilled jobs tend to be cash positive, but only if the owner has paid.
For your data teamFormula variants, tables, SQL sketch, and dashboard spec
Formula details
cash_received = SUM(owner_payments applied to job invoices)
cash_paid = SUM(ap_payments for job invoices) + SUM(payroll_paid by job)
cash_position = cash_received - cash_paid
Worked example detail
| Job | Received | Paid | Position |
|---|---|---|---|
| 2417 | $990,000 | $845,000 | $145,000 |
| 2420 | $150,000 | $225,000 | −$75,000 |
| 2431 | $1,450,000 | $1,560,000 | −$110,000 |
| Total | −$40,000 |
Tables and fields
| Table | Fields | Notes |
|---|---|---|
ar_payments |
invoice_id, paid_at, amount | |
ap_payments |
ap_invoice_id, paid_at, amount | |
ap_invoices |
ap_invoice_id, job_id | |
payroll_job |
job_id, pay_date, amount |
SQL sketch
SELECT job_id, SUM(received) - SUM(paid) AS cash_position FROM (
SELECT i.job_id, p.amount AS received, 0 AS paid FROM ar_payments p JOIN ar_invoices i USING (invoice_id)
UNION ALL SELECT a.job_id, 0, p.amount FROM ap_payments p JOIN ap_invoices a USING (ap_invoice_id)
UNION ALL SELECT job_id, 0, amount FROM payroll_job) x
GROUP BY job_id;
Build spec
Copy this into a ticket. It lists the grain, inputs, logic, and edge cases.
metric: construction.cash_flow_by_job
grain: one row per job per month, cumulative
inputs:
- owner payments
- AP payments
- payroll by job
logic:
- received = owner payments applied to job
- paid = AP payments + payroll
- position = received - paid
edge_cases:
- unapplied cash: show as unassigned
- joint checks: record once
- voided checks: exclude
As a dashboard card
- Diverging bar per job, with over/under billing as a second column, and a cumulative cash line.
Common mistakes
- Using invoice dates instead of payment dates.
- Including internal equipment allocations as cash.
- Ignoring unapplied cash.