How this started
I kept getting the same question in two different shapes.
The first shape came from me. I like running open-source tools on my own infrastructure instead of paying for the hosted version. Before I clone a repo and deploy it, I want to know one thing: what will this cost me every month? Not the server alone. The database, the email provider, the analytics, the queue, the storage, all of it. Most READMEs tell you how to run a project. Almost none tell you what it costs to keep it running.
The second shape came from clients. When I build something for a client, the conversation always gets to "so what will this cost us per month?" I used to answer in a chat message. Then the client would forward my message to their CTO or their co-founder, someone would ask "what if we get 10x the users?", and I'd redo the maths in another message. The numbers lived in screenshots and WhatsApp threads.
What I wanted was one file. Something I could hand to a client, they could open in a browser, change the user count themselves, and forward to whoever signs the cheques. That's how StackBudget started: a Claude Code skill that reads a repo and returns a single HTML cost calculator anyone can open.
But the skill only automates a process you can do by hand. So this post covers the manual way first, the hidden costs most estimates miss, and the cheaper swaps that cut the bill. The skill is at the end.
Running cost vs building cost
These are two different numbers, and mixing them up is how estimates go wrong.
- Building cost is the one-time work: design, development, your time or a developer's invoice.
- Running cost is the monthly bill to keep the product alive: hosting, database, email, analytics, AI tokens, storage, logs and payment fees.
This post is about running cost. It's the number that grows with every user you add, and the one that quietly kills small SaaS products. A product that costs $20 a month at launch can cost thousands at scale if the stack charges per request, per event or per seat.
I've written about how we keep ihatereading.in under $100 a month at 10k visitors. Most of that came from understanding exactly which line items scale with traffic.
Step 1: Read the repo like a bill
You don't need AI to do a first estimate. You need about 30 minutes and four files.
Start with package.json
Every dependency that talks to a paid service is a line on your future bill. Open package.json and sort the dependencies into two groups:
- Free libraries: React, Tailwind, Radix, date libraries, utility packages. These cost nothing to run.
- Service SDKs: anything named after a company.
@supabase/supabase-js,stripe,posthog-js,resend,@aws-sdk/client-s3,@upstash/redis,openai,@clerk/nextjs,@sentry/nextjs. Each one is a vendor with a pricing page.
Ignore devDependencies for running cost. Test runners and linters don't bill you in production.
In a typical SaaS repo, most packages are free libraries. When we scanned OpenNote, one of our open-source apps, 62 of its 63 packages were free. The cost hides in the handful that aren't.
Then read the env example file
.env.example is the most honest document in any repo. Every key that ends in _API_KEY, _SECRET or _URL points at an external service:
# Key names only. Never open the real .env.
grep -hoE "^[A-Z_]+=" .env.example .env.sample 2>/dev/null | sort -uDATABASE_URL is a database. RESEND_API_KEY is an email bill. OPENROUTER_API_KEY is an AI bill. S3_ENDPOINT is storage.
Then grep for API calls the manifests don't show
Some services don't have an SDK in package.json at all. They're called with plain fetch. This is the step people skip:
# Every external API the code calls
grep -rhoE "https://[a-z0-9.-]*api[a-z0-9.-]*\.[a-z]+" src lib app --include=*.{js,ts,jsx,tsx} | sort | uniq -c
# Every environment variable the code actually reads
grep -rhoE "process\.env\.[A-Z_]+" src lib app | sort -uWhen I ran a dependency scan on OpenNote, it found only one paid service: hosting. But OpenNote calls OpenRouter for its AI features through a plain fetch in lib/ai/openrouter.js. There's no SDK, so nothing in package.json gives it away. If I'd stopped at the manifest, I'd have missed the AI bill entirely.
Finally, check where it deploys
Deploy files tell you which hosting bill you're on:
vercel.jsonmeans Vercel.wrangler.tomlmeans Cloudflare Workers.fly.toml,Dockerfileordocker-compose.ymlmeans a server or container you pay for by the month..github/workflows/*.ymlshows what runs in CI and where it deploys.
Put it in a table
Now make one row per service with four columns: the unit it bills by (requests, GB, events, emails, seats), the free tier, the price after the free tier, and your expected usage. Estimate usage at three levels, say launch, growth and scale, because the cheapest option at 100 users is often the most expensive at 50,000.
Step 2: Find the hidden costs
The obvious costs are hosting and the database. These are the ones that show up later and surprise people:
- Per-seat pricing. Vercel Pro is $20 per seat per month, so a team of four pays four times before a single visitor arrives. Many observability and error-tracking tools also price by seat.
- Server-rendered requests. On Vercel, every server-rendered page uses Active CPU and memory that's billed on top of the plan once you pass the included usage. A mostly static site and a fully server-rendered one can have very different bills at the same traffic.
- Bandwidth and egress. Vercel Pro includes 1 TB of transfer, then charges $0.15 per GB. AWS S3 charges for data leaving it. Cloudflare R2 charges no egress fees, which is why it matters for anything that serves files.
- Logs and traces. Logging is free until it isn't. Grafana Cloud's free tier includes 50 GB of logs and 50 GB of traces with 14-day retention, then you pay per GB. Verbose logging in a busy API fills that quickly.
- Idle compute. Serverless Postgres like Neon bills compute per hour. If background workers keep the database awake, it never scales to zero, and you pay for it running all month.
- Queue polling. Redis-backed queues poll constantly, even with no jobs. On a per-command plan such as Upstash, those idle polls are billed commands.
- Analytics events. PostHog is free up to 1M events a month, then charges per event. Autocapture on a busy app burns through that faster than people expect.
- Free tiers that pause or cap. Supabase's free plan pauses a project after a week without activity. Free tiers are fine for testing, but check the cap before you build a launch plan on one.
- Preview deployments and builds. Every pull request that creates a preview deployment uses build minutes and sometimes compute.
- Payment fees. These aren't a monthly line, they're a percentage of revenue. Stripe's standard US card rate is 2.9% + 30¢ per transaction, with extra fees for international cards and currency conversion. Merchant-of-record providers charge more per transaction, because they also handle sales tax for you.
- AI tokens. Usually the line that grows fastest. Multiply generations per user by tokens per generation by your model's price per million tokens. A cheaper model for simple tasks can cut this by an order of magnitude.
- Email extras. Sending is cheap. A dedicated IP for better deliverability on Amazon SES is $24.95 a month on top.
Step 3: Swap toward cheaper and open-source options
Once you can see the bill, you can cut it. These are the swaps I look at first, by category. None of them is free of trade-offs, so each comes with what you give up.
| Category | Common default | Cheaper or open-source option | What you give up |
|---|---|---|---|
| Hosting | Vercel Pro | Cloudflare Workers ($5/mo paid plan, static assets free, no egress) or a VPS with Coolify | Vercel's polished Next.js integration and preview workflow |
| Framework | Next.js with heavy server rendering | TanStack Start, Astro, or a Vite SPA | Next.js ecosystem features; some migration work |
| Database | Supabase, Firebase or Convex | Neon serverless Postgres, or self-hosted Postgres | Built-in auth, storage and realtime that BaaS platforms bundle |
| Auth | Clerk or another hosted auth service | Better Auth or Auth.js, running in your own app | Prebuilt UI, user dashboards, and someone else handling security |
| Payments | Stripe with your own tax setup | Polar or Dodo Payments as merchant of record | Lower per-transaction fees, in exchange for tax handling |
| Analytics | PostHog Cloud, uncapped | PostHog with a billing cap, or self-hosted Umami | Session replay, feature flags, and other product analytics depth |
| Resend | Amazon SES | Resend's developer experience and React Email tooling | |
| Storage | AWS S3 | Cloudflare R2 | Some AWS-only integrations |
| Logs and tracing | Paid APM | Grafana Cloud free tier, or self-hosted SigNoz | Retention length and managed alerting |
| Testing | Paid cloud browser grids | Playwright in GitHub Actions | Real-device coverage across many browsers |
| Deployment and CI | Vercel builds | GitHub Actions plus Coolify or Dokploy on a VPS | One-click deploys; you own the server now |
A few notes on these:
- The framework swap is really a rendering swap. Next.js itself is free. The cost comes from server-rendering every request on a platform that bills compute. You can cut a lot of the bill by making more pages static, even if you stay on Next.js. I went deep on this in why our websites are slow.
- Merchant of record isn't automatically cheaper. Stripe's base card fee is lower. Polar and Dodo cost more per transaction but act as the seller and handle global sales tax. For a solo founder selling worldwide, that trade is often worth it. For a bigger team with a finance person, Stripe usually wins.
- Self-hosting moves cost, it doesn't delete it. A self-hosted Postgres or Umami needs a server, backups and your time. Count the VPS in the bill. Count your hours too.
- Free tiers are a launch strategy, not a scale strategy. Plan the paid tier you'll move to before you hit the cap.
If you're starting a new project and want these defaults baked in from day one, my SaaS starter kit and the free Next.js boilerplates list are good places to start.
Step 4: Share the estimate with the people who pay
An estimate that lives in your head doesn't help a client. The format matters as much as the numbers:
- One file, not a thread. A client should be able to forward a single thing to their CTO or co-founder without you in the loop.
- Inputs they can change. The first question is always "what if we have 10x the users?" Let them answer it themselves.
- Every number tied to a reason. "Hosting: $40" means nothing. "Hosting: $40, because Next.js is server-rendering on Vercel Pro" starts a useful conversation.
- The cheaper path next to the current one. Founders don't only want to know the cost. They want to know how low it could go, and what they'd trade to get there.
This is exactly the part I got tired of doing by hand.
Check your estimated budget with StackBudget
StackBudget is the free, open-source Claude Code skill I built to do all four steps above for any repo.
Point it at a codebase: the folder you're in, a local path, or any GitHub repo, public or private. It returns one interactive HTML calculator of the monthly running cost.
Install it:
git clone --depth 1 https://github.com/shreyvijayvargiya/stackbudget-calculator /tmp/stackbudget \
&& mkdir -p ~/.claude/skills \
&& cp -r /tmp/stackbudget/skills/stack-budget ~/.claude/skills/ \
&& rm -rf /tmp/stackbudgetRun it in Claude Code:
/stack-budget # the current folder
/stack-budget owner/repo # any GitHub repoOr just ask: "What would it cost to run this repo at 50k users?"
What it does:
- Step 1, automated. It scans every manifest (
package.jsonincluding workspaces,requirements.txt,pyproject.toml,go.mod,Cargo.tomland more), deploy files and env key names, and maps packages to paid services. Then Claude reviews the scan against how the repo actually deploys, drops dev-only false positives and adds services the rules missed. That review is how it catches cases like OpenNote'sfetch-based OpenRouter calls. - Step 2, priced. Each line names the packages that cause it, split into frontend and backend, with launch, growth and scale presets. Prices come from vendor pricing pages and are dated in the repo.
- Step 3, a migration planner. Every service has a "Migrate to" picker: Cloudflare instead of Vercel, self-hosted Postgres instead of Neon, a cheaper model, and so on. "Pick cheapest stack" chooses the lowest option per row and skips free tiers your usage would break. Self-hosted choices add server cost, so the savings shown are net.
- Step 4, shareable. It's one HTML file, in USD and INR, with light and dark themes, and it works on a phone. Send it to a client, attach it to an issue, or forward it to your CTO.
A real example from the repo: for Reloop, an open-source Resend alternative with 227 packages and 10 paid services, the managed stack at 5,000 users and 1M emails a month comes to about $359 a month. "Pick cheapest stack" brings it to about $96 a month. You can open that report in your browser to see what your clients would get.
What it won't do: it only reads. It never commits, pushes or opens pull requests, and it never opens your real .env files, only the key names in example env files. Remote repos are cloned to a temporary folder and deleted after the report is built.
If you try it, star the repo and open an issue for any vendor it doesn't price yet. Pull requests with new pricing rules are welcome. More open-source tools like this are in the iHateReading open-source projects post, and new ones land in the monthly magazine.