Arron Bennett, Founder of Bennett Financials
Ask the owner of an engineering firm how next year looks and you'll usually hear one number: the backlog. "We've got $5.3M signed." It sounds safe. It tells you almost nothing about when that money turns into revenue, and timing is the whole question.
Backlog forecasting fixes that. You take every signed project, spread its remaining fee over the months the work will actually happen, and add the months up. The result is a revenue curve, and the curve usually shows a cliff that the single number hides.
This post builds that curve in plain Python for a hypothetical 44-person MEP engineering firm: $7.1M of revenue last year and $5.3M of signed backlog. Every figure is example math. Swap in your own projects.
Key takeaways
- A backlog total says how much work is signed. A burn schedule says when it becomes revenue. You need both.
- In this example, $5.3M of backlog is nine months of revenue, yet it covers only 43% of each month from July onward.
- The gap to fill over the next 12 months is about $2.04M, which at a 35% win rate means roughly $5.83M of proposals.
- Track book to bill monthly. Under 1.0 for a year is how a cliff like this gets built.
What is backlog forecasting?
Backlog forecasting turns signed but unearned fees into a month-by-month revenue forecast. For each project you set the remaining fee, the start month and how long the work will take, then spread the fee across those months. Summing every project by month shows how much of each future month is already covered and how much still has to be won.
The total backlog is a stock. Revenue is a flow. A firm with $5.3M signed can still have a thin summer if most of that money sits in one long hospital job and a handful of projects that finish by spring. That's why I'd rather see the curve than the total.
For project-based firms, the curve is also the best early warning you have. The P&L tells you what happened last month. The backlog curve tells you what will happen in month seven, while there's still time to do something about it.
Why isn't the backlog total enough?
Because it hides timing. "Nine months of backlog" sounds like nine full months of work. In practice, some projects burn fast and finish early, others stretch past the year, and new starts slip. The total stays the same while coverage of specific months collapses. You find out when utilization drops and the team is already on payroll.
It also hides the trend. A backlog that held at $5.3M because you won a lot is different from one that held because projects slowed down. Book to bill, new signed work divided by revenue for the same period, tells you which. Here, say the firm signed $6.4M of new work over the last 12 months against $7.1M of revenue. That's a book to bill ratio of about 0.90. Backlog fell by $700,000 in the year, from about $6.0M to $5.3M.
There's a second source of work the backlog never shows: clients who come back. In this short I talk about repeat rate, how often a client comes back in a year, as the number that lets you predict next year's revenue. For an engineering firm, that's the repeat-client side of this forecast.
What does the Python look like?
One list of signed projects with four fields: name, remaining fee, start month and months to finish. The script spreads each fee evenly across its months, sums the months, and compares each month with last year's monthly revenue. It prints coverage, the monthly gap, the 12-month total and the proposals you'd need at your win rate.
Even burn is a simplification. Real projects ramp up, peak through design development and taper during construction administration. If your project management tool exports planned hours by month, use those instead. The structure doesn't change. Standard library only, and you can paste it and run it.
BACKLOG = [ # signed work: (project, remaining fee $, start month from now, months to finish) ("Hospital wing MEP", 1_450_000, 0, 14), ("Office tower retrofit", 880_000, 0, 12), ("K-12 school renovation", 620_000, 0, 8), ("Senior living campus", 560_000, 2, 10), ("Lab fit-out", 540_000, 0, 6), ("Data center cooling", 410_000, 0, 5), ("Municipal library", 300_000, 0, 6), ("Hotel renovation", 300_000, 1, 6), ("On-call small jobs", 240_000, 0, 12), ] MONTHS = ["Nov", "Dec", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct"] RUN_RATE = 7_100_000 / 12 # last year's revenue, per month WIN_RATE = 0.35 # share of proposed fees you win, from your own history curve = [0.0] * 24 for name, fee, start, months in BACKLOG: for m in range(start, start + months): curve[m] += fee / months # even burn schedule; swap in your own print(f"signed backlog ${sum(f for _, f, _, _ in BACKLOG):,.0f} = " f"{sum(f for _, f, _, _ in BACKLOG) / RUN_RATE:.1f} months of revenue") print(f"{'month':<6}{'from backlog':>14}{'coverage':>10}{'gap':>11}") gap_total = 0 for i, name in enumerate(MONTHS): gap = max(RUN_RATE - curve[i], 0) gap_total += gap print(f"{name:<6}{curve[i]:>14,.0f}{curve[i] / RUN_RATE:>10.0%}{gap:>11,.0f}") year = sum(curve[:12]) print(f"next 12 months from backlog ${year:,.0f} ({year / 7_100_000:.0%} of last year)") print(f"gap to fill ${gap_total:,.0f}; proposals needed at {WIN_RATE:.0%} win rate ${gap_total / WIN_RATE:,.0f}") print(f"backlog burning after month 12: ${sum(curve[12:]):,.0f}") Output:
signed backlog $5,300,000 = 9.0 months of revenue month from backlog coverage gap Nov 496,405 84% 95,262 Dec 546,405 92% 45,262 Jan 602,405 102% 0 Feb 602,405 102% 0 Mar 602,405 102% 0 Apr 520,405 88% 71,262 May 380,405 64% 211,262 Jun 330,405 56% 261,262 Jul 252,905 43% 338,762 Aug 252,905 43% 338,762 Sep 252,905 43% 338,762 Oct 252,905 43% 338,762 next 12 months from backlog $5,092,857 (72% of last year) gap to fill $2,039,357; proposals needed at 35% win rate $5,826,735 backlog burning after month 12: $207,143 What does the revenue curve say about this firm?
The firm is full through spring and exposed after it. January to March run at 102% of last year's monthly revenue, so the team is stretched. From May, coverage falls fast, and July to October sit at 43%. The backlog total looked comfortable. The curve shows a summer cliff that new wins have to fill.
Three numbers matter here:
- $5,092,857 of the next 12 months is already signed, about 72% of last year's revenue. The rest, $207,143, burns after month 12, mostly the tail of the hospital job.
- The gap is $2,039,357. That's the revenue that has to come from work not yet signed, before you even think about growth.
- At a 35% win rate, that's roughly $5.83M of proposals. Treat it as a floor. Work you win in June won't all burn by October, so the real pipeline you need is bigger.
The over-coverage in January to March is a signal too. It means overtime, outside help or late deliverables, and a reason to stagger new starts instead of saying yes to every one at once.
How do you use the forecast to make decisions?
Use the coverage line to time hiring, pursuit effort and cash. If coverage six months out is under about 70%, pursuit becomes the priority now, not in month five. If coverage is over 100%, slow new starts or plan the capacity. Review it monthly alongside book to bill and win rate, the key performance indicators that move the curve.
A few rules I'd keep:
- Update the start months honestly. Slipped notices to proceed are the most common reason a backlog forecast flatters you.
- Keep a separate line for repeat clients. If, say, 60% of last year's $6.4M of signed work came from clients who'd hired you before, that's about $3.84M of next year's pipeline to protect with relationships, not proposals.
- Don't hire against the January peak. Hire against the coverage six to nine months out.
- Watch cash alongside revenue. Coverage tells you what you'll bill, and your collection days tell you when it turns into operating cash flow.
I've written a longer guide to backlog forecasting for project-based firms, and one on reading the book-to-bill ratio in a service business.
What should you do on Monday?
Export your signed projects with remaining fee, expected start and duration. Paste them into the script, set your own run rate and win rate, and run it. Then look at coverage six months out. If it's under 70%, put pursuit on this week's agenda, and agree who owns which proposals.
FAQ
What is a good book to bill ratio for an engineering firm?
Above 1.0 means backlog is growing, below 1.0 means it's shrinking. A single quarter below 1.0 isn't a crisis. A full year below it, as in this example, is how a revenue cliff gets built.
How many months of backlog should a firm have?
It depends on project length. Months of backlog is a useful headline, but coverage by month is what tells you whether next summer is safe.
Should backlog forecasting use fees or hours?
Fees for the revenue curve, hours for capacity. If your tools hold planned hours by month, convert them to fee and use that shape instead of an even burn.



