When someone asks “how many months can I live without a salary?”, dividing savings by monthly expenses gives a useful first guess, but it hides two decisions: which expenses are essential and what happens to income during the transition. I built this calculator around explicit scenarios so a cautious budget and a current-lifestyle budget can be compared instead of blended into one optimistic number. This is aimed at anyone planning a resignation, layoff buffer, or career break and wanting to understand the model rather than trust one impressive number.
Net burn is the quantity that matters
Each scenario has savings, transition income, an annual savings rate, and four expense buckets: rent or mortgage, living costs, insurance, and other essentials. The calculation sums expenses, subtracts income, then clamps negative burn to zero:
const monthlyExpense = cleanNumber(clean.rent)
+ cleanNumber(clean.living)
+ cleanNumber(clean.insurance)
+ cleanNumber(clean.other);
const rawNetBurn = monthlyExpense - income;
const netBurn = Math.max(0, rawNetBurn);
Suppose the four buckets total 50,000 and temporary income is 12,000. The model calls the burn 38,000 per month. If income is 55,000, rawNetBurn is negative, but netBurn becomes zero. The result is labeled theoretically indefinite rather than claiming that savings become infinite. That distinction matters: a zero modeled burn means this particular set of assumptions does not consume the starting savings; it does not mean the person's life has no expenses.
Every numeric field passes through cleanNumber, which turns non-finite or non-positive values into zero. Annual rate is also capped at 100 percent. Those choices make pasted blanks and malformed input safe, but they also mean a typo can silently become zero. I would still review the displayed monthly expense before using the result for a real decision.
Daily simulation and the 30.4375-day compromise
For a finite runway, the component divides monthly net burn by DAYS_PER_MONTH, which is exactly 30.4375. It then simulates one day at a time. Interest is converted from the annual rate to a daily compound rate:
const dailyNetBurn = netBurn / DAYS_PER_MONTH;
const dailyRate = annualRate > 0
? Math.pow(1 + annualRate / 100, 1 / 365) - 1
: 0;
let balance = savings;
let totalDays = 0;
while (balance > 0 && totalDays < 36500) {
balance = balance * (1 + dailyRate) - dailyNetBurn;
totalDays += 1;
}
Applying growth before that day's burn gives the balance a small amount of interest before expenses leave it. The loop stops once the balance is no longer positive or after 36,500 days, a defensive ten-year ceiling. The displayed runway converts the resulting days back into months and days using the same 30.4375 average. This is more honest than pretending every month has 30 days, but it is still an average: rent due dates, quarterly bills, and leap years are not modeled individually.
The zero date is calculated by adding the rounded simulated days to Date.now(). Treat it as a planning marker, not a promised payday. A real account may earn interest monthly, pay bills on different dates, or receive a severance payment that belongs in transition income.
The monthly preview is a second, bounded view
The result also builds balanceRows for a monthly preview. It uses a monthly rate and applies interest before subtracting the same monthly burn:
const monthlyRate = cleanNumber(scenario.annualRate) / 100 / 12;
let balance = savings;
const maxMonths = Math.min(36,
Math.max(1, Math.ceil((totalDays || 0) / DAYS_PER_MONTH)));
for (let month = 1; month <= maxMonths; month++) {
balance = Math.max(0, balance * (1 + monthlyRate) - netBurn);
balanceRows.push({ month, balance });
if (balance <= 0) break;
}
This can differ slightly from the daily answer because it is a monthly summary with a monthly rate, not a replay of every daily balance. The 36-month cap keeps the page readable and avoids pretending a long-horizon projection is precise. If the daily calculation says 14 months, the preview stops around that point; if a balance lasts longer, the preview intentionally shows only the first three years.
The two views answer slightly different questions. The daily loop is the source for the runway duration and zero date, while the rows are a communication layer for scanning how the balance changes month by month. That separation is useful when building a financial UI: a chart should not quietly become a second, conflicting calculator. If I changed the month preview to drive the headline number, I would also have to decide how to reconcile daily interest, bill timing, and the fractional average month.
Scenarios are saved locally so assumptions can evolve
The page supports adding, duplicating, deleting, clearing, and switching scenarios. A watcher serializes the scenario array to begoodtool_noIncomeRunwayCalculator_v1 in localStorage, and the comparison table runs the same calculation for every scenario. That makes “what if I cut rent?” a side-by-side change rather than a memory exercise. A useful walkthrough is to duplicate a baseline, set income to zero in one copy, then reduce living costs in another; the table exposes which assumption actually moves the zero date.
Important edges remain: positive cash flow is reported as indefinite, a zero-savings positive-burn case is zero days, annual taxes must be translated into a monthly bucket, and changing devices loses local scenarios. I turned this scenario model into a small free tool: No-Income Runway Calculator.
Top comments (0)