Every retirement calculator I have used has the same flaw. You enter your numbers, it produces a single figure with impressive precision, and that figure is wrong in a way the interface conceals.
$1,847,392 at age 65. Seven significant figures on a forty year projection whose inputs include a return assumption nobody can predict. That number is not a forecast, it is a scenario, and displaying it that way tells the user something false about how much anyone knows.
Retire Goals was my attempt to build the version that is honest about that while still being useful, because “nobody knows” is true and also completely useless as product guidance.
The actual problem I was solving #
It was not the math. Compound interest is a formula you can write in one line.
The problem is motivational. Retirement saving is a forty year commitment where nothing visible happens for the first decade. You contribute five hundred dollars a month for three years, you have eighteen thousand dollars, and it feels like you are pushing money into a hole. The exponential curve is nearly flat at the start, which is exactly the period when people quietly stop.
The reason the math works is entirely in the back half, and the back half only exists if you survive the front half. The arithmetic on that is here.
So the app’s real job is to make the invisible visible: show that the flat part is expected, show where the curve goes, and give someone in year three a reason to still be doing this in year eight.
Why one number is the wrong output #
The single-figure design fails because of how sensitive the result is to an input nobody knows.
Take $500 a month for 35 years:
| Assumed return | Result |
|---|---|
| 5% | ~$570,000 |
| 6% | ~$715,000 |
| 7% | ~$900,000 |
| 8% | ~$1,150,000 |
A one percentage point change in an assumption moves the answer by around twenty percent. Two points nearly doubles it. And the actual realized return over any given 35-year period is not knowable in advance.
Showing $900,000 as the answer implies a precision the model does not have.
What I did instead: make the return assumption prominent and adjustable, right next to the result, rather than buried in settings with a default nobody examines. Drag it and watch the projection move. That interaction communicates the uncertainty better than any disclaimer, because the user discovers it themselves in about four seconds.
The intended reaction is “oh, this depends enormously on something nobody knows.” That is the correct reaction, and most calculators actively prevent it.
The design problem of a flat curve #
Here is a real problem I did not anticipate. In year two, the projection chart is a nearly straight line at the bottom of a graph whose vertical axis is scaled to a number in the high hundreds of thousands. Your actual balance is a barely-visible sliver.
That is a mathematically accurate chart that is emotionally discouraging, which for an app whose entire purpose is sustaining motivation is a failure.
I tried a log scale on the vertical axis. Technically elegant, since steady exponential growth becomes a straight line. Also incomprehensible to anyone who has not taken a math class, and it makes the growth look linear, which undersells the actual point.
I tried auto-scaling to current progress, zooming the axis to your actual balance so early progress looks dramatic. This made the numbers feel good and destroyed the sense of scale, which is the thing that motivates the behavior. It also meant the axis kept changing, so progress between sessions was invisible.
What shipped is the full-scale projection with the target visible, plus a separate and prominent progress-toward-goal indicator and near-term milestones. So you see the whole mountain and you also see that you are 4.2% of the way up and that you will hit your next milestone in seven months.
Long horizon for context, short horizon for feedback. That combination is what makes it survivable.
Splitting goals up #
The other thing that helped was letting people set multiple goals rather than one enormous retirement number.
One goal of $1.5 million at 65 is abstract and unreachable-feeling. An emergency fund goal of $20,000, a house down payment goal, and a retirement goal are three separate things, two of which you will actually complete, and completing things is what keeps people engaged with a system.
This was not in my original design. It came from realizing that I did not open my own prototype because it only ever told me I was 3% done with something forty years away.
The math, and the part that bit me #
The core projection is future value of a series with an initial balance:
FV = P(1+r)^n + PMT × [((1+r)^n − 1) / r]Straightforward. Where it got fiddly:
Compounding frequency. Contributions are monthly, so use monthly compounding with the annual rate divided by twelve. The difference between monthly and annual compounding on a forty year projection is several percent, which is large enough to matter and small enough that nobody notices you got it wrong.
Contributions at the start or end of the period. Whether a month’s contribution earns that month’s return changes the result slightly. I picked end-of-period, which is the conservative choice, and documented it.
Real versus nominal. A million dollars in 2066 is not a million dollars today. Inflation over forty years at three percent cuts purchasing power by roughly two thirds. Showing a big nominal number without acknowledging that is one of the standard ways these tools mislead. There is an inflation-adjusted view, and it is deflating in exactly the way it should be.
Floating point. Money math in binary floating point accumulates rounding error, and in a loop over 480 months it compounds visibly. Two different code paths computing the same projection disagreed by a few dollars, which showed up as a display inconsistency between the chart and the summary. The fix is the standard one: work in integer cents internally and format for display, with a single source of truth for the calculation rather than two implementations that ought to agree.
Dates. Contribution scheduling across time zones and daylight saving transitions produced an off-by-one-day bug that occasionally double-counted a month. Date handling is the tax you pay on every application that tracks anything over time, and I have never once estimated it correctly.
No accounts, no server #
Same architecture as everything else I build. Local storage, no login, no sync, no backend.
The reasoning is stronger here than usual. This app knows your savings balance, your contribution rate, your target retirement date, and your goals. That is a detailed financial profile. There is no version of me that wants to hold a database of that for strangers, and there is no version of a sole-developer app where I could credibly promise to secure it forever.
With no server there is nothing to breach, nothing to subpoena, no subscription needed to cover hosting, and no privacy policy that requires you to trust me. The data is on your device, which is where a person’s finances should live. The same argument, applied to AI, is in what happens to your data when you use AI.
The cost is the usual one: no sync across devices, and no backup if you lose the phone. For a tool you update monthly rather than daily, that is a trade I am comfortable with, and users can re-enter a handful of numbers in a few minutes.
What it deliberately does not do #
No investment advice. It does not tell you what to invest in. It projects a number based on a return you specify.
No account connections. It does not read your brokerage balance. You enter contributions yourself, which takes thirty seconds a month and means the app never touches a credential.
No Monte Carlo simulation. I considered it seriously. Running a thousand randomized return paths and showing a probability distribution is more honest than a single curve. I left it out because the output is hard to interpret for a general audience and it invites a different false precision, where people read “87% success probability” as a real number rather than as an artifact of the assumed return distribution. This one I still go back and forth on.
No tax modeling. Roth versus traditional changes the after-tax value of a balance substantially, and modeling it properly requires assumptions about future tax rates that are even less knowable than returns. That decision is its own article.
Every one of those is a real limitation. Each was a choice between doing something partially and not claiming to do it at all, and I would rather the app be narrow and honest than broad and confidently wrong.
Lessons #
The hard part of a finance app is not the finance. The formula took an hour. The chart design took weeks, because the emotional response to an accurate chart was the actual product problem.
Precision and accuracy are different things, and interfaces routinely display seven digits of precision on top of one digit of accuracy. Making the uncertainty interactive was the best design decision in the app.
Milestones beat targets. People need to complete things, and a forty year goal completes zero times.
Money math needs integer cents. Every developer learns this and most of us learn it from a bug report.
And local-first removes an enormous amount of work. The amount of software that has a backend purely out of habit is larger than people think.
The financial reasoning behind the app is in how much you actually need to retire and why saving in your twenties matters so much. Other builds: a credit card tracker, a GPS speedometer, and an offline AI chat app.