Build Sheet · July 2026
How SunnySky is built
A dark-mode, social-first weather app that reads sevenindependent forecasts and shows you where they disagree. One TypeScript codebase ships it to iPhone, Android and the web. Here's what I used, why I picked it, and what it costs me to run.
- TypeScript
- 26,492
- Forecast sources
- 6
- Data providers
- 20
- Edge functions
- 12
- Cost today
- $8/mo
01The shape of it
It's one repo with four packages inside. Two of them are the actual apps — the phone app and the website. The other two are the stuff both apps have to agree on: all the weather logic, and the design tokens.
That split is basically the whole architecture, and it's the decision I'd defend hardest. The maths that draws the consensus line on the chart is literally the same function that fills in the iPhone widget, because they both import it from the same file. There's no second copy to drift out of sync. When I fixed a rounding bug in it once, the app, the website and the widget all got the fix at the same time without me touching three files.
Everything below hangs off that idea: keep the thinking in one place, keep the platforms dumb, and don't pay for anything the government already gives away.
02What I'm actually using
The phone app
I'm a solo dev. If I had to maintain a Swift app and a Kotlin app and a web app separately, I'd ship nothing. So the whole client is one codebase.
Stack.Protected— the whole onboarding → login → app gate is four lines of “this screen only exists if you're signed in”, instead of redirect logic smeared across every screen.The website
sunnyweather.co is the marketing site, and it also serves the entire app as a web build at /app — so you can try the real thing without installing anything.
The backend
This is the part I'd have expected to be hardest and it turned out to be the easiest. It's all one product.
Where the weather comes from
This is the actual product. Most weather apps resell one forecast. I pull seven, plus a pile of government feeds, and show you where they disagree.
Shipping and keeping it alive
03What it costs me
Two columns — what I'm actually paying right now before launch, and what it turns into at roughly 2,000 installs with 50 people subscribed.
| Service | What I need | Now | At 2k installs |
|---|---|---|---|
| Apple Developer | $99/yr, non-negotiable | $8.25 | $8.25 |
| Open-Meteo | API Standard — commercial licence | $0 | $29.00 |
| Supabase | Pro — backups, and it stops auto-pausing | $0 | $25.00 |
| Vercel | Pro — required once I charge money | $0 | $20.00 |
| Pirate Weather | Paid once I outgrow the free calls | $0 | $5.00 |
| Apple WeatherKit | 500k calls included with the $99 | $0 | $0 |
| OpenWeather | Free tier is plenty | $0 | $0 |
| Google Weather | Maps Platform free calls for now | $0 | $0 |
| Google Pollen | 5,000 calls free, then $10/1,000 — cached 6 h per area | $0 | $0 |
| Google Routes | 10,000 calls free, then $5/1,000 — Pro only, 60/day each | $0 | $0 |
| NOAA / NASA / USGS | Public data, no key, no bill | $0 | $0 |
| Sentry | Free — 5k errors/mo | $0 | $0 |
| EAS Build | Free — 15 iOS builds/mo | $0 | $0 |
| RevenueCat | Free under $2,500/mo revenue | $0 | $0 |
| What I pay | per month | $8.25 | $87.25 |
And against that, 50 people paying $2.99:
Break-even is about 33 subscribers. The only reason that number is achievable is that the expensive-sounding parts — seven forecasts reconciled, ten models polled, months of accuracy history — mostly run on free government data and on maths that happens on your phone.
The two Google rows are the ones I watch, because they're the only things here billed per request rather than per month. Both sit at zero by construction rather than by luck. Pollen is a daily index, so it's cached six hours per area— a whole city asking at once is one call, and 5,000 calls a month is a lot of cities. Routes is heavier, so it's Pro-only, capped at 60 trips per person per day, refuses the public key outright, caches by rounded coordinates, and asks for the traffic-unaware tier — which is both the cheapest and the honest one, since live traffic at the moment you ask describes none of the departures being compared. If either line ever stops reading $0, it'll be because the app got popular, and I'd rather find that out from this table than from a bill.
04Stuff I learned the annoying way
Two “free” tiers you can't use commercially
Open-Meteo's free API is non-commercial, and their terms specifically name “apps that have subscriptions” as commercial. Vercel's Hobby plan says the same thing. Both are free today, and both quietly become licence breaches the day I charge anyone — regardless of how little traffic I use.
Nothing warns you. It's $49/mo between them and it has to be paid before the subscription goes live, not after.
One of my Pro features might sit on a $99 plan
Forecast drift — showing how a day's forecast has been revised across recent model runs — needs Open-Meteo's Previous Model Runs API, and that looks like it requires their Professional plan at $99/mo instead of Standard at $29.
That $70 flips +$40/mo into −$30/mo. I need to confirm it with them directly before buying, and if it's true then drift either earns its own $70 or it gets cut.
Where the money isn't going
No servers. No Kubernetes, no Redis, no message queue, no CDN bill, no analytics vendor, no email service, no Mac in a cupboard running builds. The database schedules its own jobs and Apple handles the billing.
05Four things I deliberately didn't use
Every one of these is a thing you'd normally reach for, and skipping them was the right call each time.
No charting library
I hand-draw the forecast chart in SVG. I needed a median line coloured by temperature along its length, every source ghosted behind it, and a scrubber snapping to 30-minute steps — and once you've fought a chart library for a day you realise drawing it yourself is the shorter path.
No map library
The radar map is about 400 lines of hand-rolled tile maths. It draws the basemap, the radar frames and the warning polygons, animates them, and behaves the same on phone and browser. Mapbox and friends bill per map load, which is exactly the cost curve I built the rest of this app to avoid.
No state management library
Just React context and some hooks. The app's state is honestly simple — a location, a forecast, a session. Redux would be ceremony for the sake of it.
No component kit
Design tokens instead. The app has a very specific look — instrument panel, monospace numbers, true-grey surfaces with no blue in them — and starting from someone else's components means fighting their defaults the whole way.