Arron Bennett, Founder of Bennett Financials
At most bootstrapped companies, engineering headcount planning happens in the founder's head. Revenue is growing, the backlog is growing faster, so you hire. A few months later the bank balance is lower than you expected and you're not sure which decision did it.
A spreadsheet fixes that. So do about 30 lines of Python, which some technical founders will actually keep up to date. This post walks through a small month-by-month cash model for deciding when the next engineer is affordable, using a hypothetical bootstrapped transactional email API at $118,000 of MRR with nine people, planning its 2027 hires.
Key takeaways
- Plan hires against monthly cash, not annual profit. The start date of each hire changes the answer.
- Use fully loaded cost: salary plus payroll taxes, benefits and equipment. Add a one-time hiring cost in the start month.
- Set a cash floor, such as three months of total costs, and treat any month below it as a no.
- In this example, one engineer in February is comfortable, a second in June dips under the floor in November, and the same second hire in October doesn't.
What is headcount planning for a bootstrapped SaaS?
Headcount planning is deciding who you'll hire, and when, based on what the business can afford month by month. For a bootstrapped SaaS without investor cash behind it, the binding constraint is the bank balance, not the budget. A good plan shows the lowest cash month for each set of hiring plans before anyone signs an offer.
Annual numbers hide the problem. A hire can look fine across the year and still push one month under the line you've promised yourself. That's why the model below runs month by month.
What inputs does an engineering headcount plan need?
Seven numbers: starting cash, current MRR, monthly growth, variable costs as a share of revenue, today's fixed costs, the fully loaded monthly cost of an engineer, and a one-time hiring cost. Add a cash floor, the minimum you'll let the bank balance fall to. Everything else is a scenario: which start month for which hire.
For the email API, all hypothetical:
- Starting cash on January 1, 2027: $420,000.
- MRR: $118,000, growing 1.5% a month.
- Variable costs, meaning sending infrastructure, payment fees and support tools: 20% of MRR.
- Fixed costs for today's nine people, tools and rent: $74,000 a month.
- One engineer, fully loaded: $17,500 a month, or $210,000 a year, covering base salary, employer payroll taxes, benefits and equipment.
- One-time hiring cost per engineer: $25,000, in the start month.
- Cash floor: three months of total costs.
In January the business makes about $20,400 of pre-tax operating profit: $118,000 of MRR, less $23,600 of variable costs and $74,000 of fixed costs. That's the cushion every hire draws on.
The model is pre-tax. Taxes matter, and the 2025 tax law changed them for software teams: domestic development costs can again be deducted in the year you pay them, while offshore development still amortizes over 15 years, per the IRS summary of the law. I've written about how that changes a domestic vs offshore development budget. Add a tax line once your accountant has given you an estimate.
What does the Python model look like?
It's one function that walks through twelve months. Each month it grows MRR, adds the cost of every engineer who has started, takes the hiring cost in the start month, and updates cash. It also tracks headroom, meaning cash above the floor, and reports the tightest month. It's plain Python with no libraries, so paste it and run it.
START_CASH = 420_000 # cash on Jan 1, 2027 MRR0 = 118_000 # January MRR GROWTH = 0.015 # MRR growth per month VARIABLE = 0.20 # sending infrastructure, payment fees, support: share of MRR FIXED = 74_000 # today's 9 people, tools and rent, per month LOADED = 17_500 # one engineer, fully loaded, per month RECRUIT = 25_000 # one-time hiring cost in the start month FLOOR = 3 # months of total costs to keep in the bank def run(starts): cash, tightest, when = START_CASH, None, None for m in range(1, 13): mrr = MRR0 * (1 + GROWTH) ** (m - 1) heads = sum(1 for s in starts if s <= m) costs = mrr * VARIABLE + FIXED + heads * LOADED cash += mrr - costs - RECRUIT * starts.count(m) headroom = cash - FLOOR * costs if tightest is None or headroom < tightest: tightest, when = headroom, m return cash, tightest, when plans = { "no hires": [], "1 hire: Feb": [2], "2 hires: Feb, Jun": [2, 6], "2 hires: Feb, Oct": [2, 10], "3 hires: Feb, Jun, Sep": [2, 6, 9], "3 hires: all in Feb": [2, 2, 2], } for name, starts in plans.items(): end, low, month = run(starts) flag = "ok" if low >= 0 else "BELOW FLOOR" print(f"{name:<23} Dec cash ${end:>9,.0f} tightest headroom ${low:>9,.0f} in month {month:>2} {flag}") Output:
no hires Dec cash $ 763,090 tightest headroom $ 147,600 in month 1 ok 1 hire: Feb Dec cash $ 545,590 tightest headroom $ 73,354 in month 2 ok 2 hires: Feb, Jun Dec cash $ 398,090 tightest headroom $ -13,274 in month 11 BELOW FLOOR 2 hires: Feb, Oct Dec cash $ 468,090 tightest headroom $ 56,726 in month 11 ok 3 hires: Feb, Jun, Sep Dec cash $ 303,090 tightest headroom $ -159,808 in month 12 BELOW FLOOR 3 hires: all in Feb Dec cash $ 110,590 tightest headroom $ -352,308 in month 12 BELOW FLOOR The cash model tells you whether you can afford the engineer. This short is about the other half of the decision, the return each hire should produce, which is the question I'd ask right after.
What does the model say about 2027 hires?
One engineer in February is comfortable. The tightest month still leaves about $73,400 above the floor. A second engineer in June pushes cash about $13,300 under the floor by November. Move that second start to October and the tightest month keeps about $56,700 of headroom. Three hires in 2027 break the floor in both timings tested.
The difference between June and October for the second hire is $70,000 of cash by December: four months of loaded cost at $17,500. Same person, same salary, different start date.
Hiring all three in February is the clearest warning. By December the business is losing about $15,300 a month before tax, and cash is about $352,300 short of the floor. The cash runway hasn't run out yet, but the trend has turned.
None of this means "don't hire". It means sequence the hires so each one starts when the business can carry it, and decide in advance what has to be true before the next offer goes out, such as MRR above a set number.
What should you change before trusting the output?
Replace every input with your own numbers, then stress them. Run growth at half your plan, add a month where a large customer churns, and check what happens if the recruiting fee lands a month before anyone starts. If a hiring plan only clears the floor with optimistic growth, it doesn't clear the floor.
Two things the simple version leaves out on purpose:
- Revenue from the new hire. The model assumes none, which is conservative. If an engineer is meant to unlock a feature customers will pay for, add that revenue as its own scenario, starting months after the hire.
- Raises and taxes. Add both once you have real numbers for them.
If you later raise funds, this same monthly view becomes the base for your revenue forecast, financial projections, scenario planning and board reporting. The SaaS financial planning framework I use builds on exactly this kind of month-by-month cash model.
What should you do on Monday?
Paste the script, replace the inputs with your real numbers, and add every hire you're considering for 2027 as its own scenario. Pick a cash floor you'd defend to a co-founder. Then write down, for each hire, the MRR level or date that has to be reached before the offer goes out, and put it in the plan.
FAQ
How much cash should a bootstrapped SaaS keep before hiring?
There's no single answer. Three months of total costs is the floor I'd start with for a profitable bootstrapped company. Pick a number you'd defend and stick to it.
What is the fully loaded cost of an engineer?
Base salary plus employer payroll taxes, benefits, equipment and software. Use the monthly figure in the model and add recruiting as a one-time cost in the start month.
Should the model include revenue from the new hire?
Not in the base case. Add it as a separate scenario with a realistic delay, so the decision doesn't depend on revenue that hasn't happened yet.