What will your app cost to run? Estimating hosting costs from 100 to 100,000 users

By

How to turn a number of users into a hosting bill: requests, bandwidth, CPU time and database writes, priced on Cloudflare, Vercel, a VPS and a PaaS, with the cost cliffs to watch for.

~~~

Pricing pages don’t tell you what your app will cost. They tell you what a gigabyte costs, what a million requests cost, what a seat costs. Turning that into a monthly bill is your job.

Most people skip that job. They pick a host because it has a free tier, and find out what it costs when the app grows. Sometimes that is a $6 surprise. Sometimes it is a $2,000 one.

This post is the method I use to estimate the bill before I deploy. It has three steps: turn users into usage, find out what each platform meters, and multiply. Then we look at where the bills jump, because they never grow in a straight line.

The prices below are the public ones I found in mid 2026. They change. The method does not.

Step 1: turn users into usage

Hosts don’t bill per user. They bill per request, per gigabyte transferred, per CPU millisecond, per database read and write, per instance, per seat. So the first step is converting “I expect 1,000 users” into those numbers.

You need a few assumptions. Here are mine for a typical web app. Change them for yours.

  • A daily active user (DAU) makes about 50 requests a day. Pages, API calls, images, scripts.
  • Each request transfers about 100 KB. Less for API JSON, more for pages with images.
  • Each request uses about 15 ms of CPU on the server.
  • With a database, each request does about 5 reads and 1 write.
  • A month has 30 days.

The formulas:

requests   = DAU × 50 × 30
egress GB  = requests × 100 KB / 1,000,000
CPU ms     = requests × 15
DB reads   = requests × 5
DB writes  = requests × 1

Let’s fill the table at four sizes. These four points are enough to see the shape of the bill.

100 DAU1,000 DAU10,000 DAU100,000 DAU
Requests / month150,0001.5 million15 million150 million
Egress15 GB150 GB1.5 TB15 TB
CPU time2,250 s6.25 hours62.5 hours625 hours
DB reads750,0007.5 million75 million750 million
DB writes150,0001.5 million15 million150 million

Two things jump out already. Egress grows into terabytes fast. And 150 million requests a month is about 58 requests per second on average, with peaks several times that. That is the point where “one small server” stops being obvious.

If your app is an API returning small JSON, cut egress by 5×. If it serves images or video, multiply it by 5× or more. The assumption that matters most is the one you should check first.

Step 2: find out what each platform meters

Every platform bills on a different set of meters. This is why the same app costs $0 on one host and $95 on another at the same traffic.

Cloudflare Workers meters requests and CPU milliseconds. Egress is free. The free plan includes 100,000 requests a day. The paid plan is $5 a month with 10 million requests and 30 million CPU-ms included, then $0.30 per million requests and $0.02 per million CPU-ms. D1, the database, bills reads at $0.01 per million and writes at $1 per million after the included amounts.

Vercel meters data transfer, function duration, builds, and seats. The Hobby plan is free with 100 GB of transfer, for non-commercial projects. Pro is $20 per seat per month with 1 TB included, then $0.15 per GB.

Netlify works the same way, with credits. Free covers 100 GB and a pool of credits that traffic, builds and functions all drain. Pro is $19 per seat with 1 TB, then $0.55 per GB.

Railway meters CPU, memory, and egress by the second, with a $5 Hobby minimum that you spend as usage credit. An always-on small service lands around $5–10. The bill moves with your traffic and with your memory leaks.

Render and Fly.io bill per instance size, per month. A $7 Render Starter service or a $3 Fly Machine costs that whether it serves one request or a million, until you need a bigger one or a second one. Egress above an allowance costs extra.

A VPS bills per server. Hetzner’s smallest cloud server is around €5 a month including an IPv4 address, with 20 TB of transfer. DigitalOcean’s is $6 with 1 TB. The meter is the server size. Nothing else moves.

AWS meters everything. Lambda requests and duration, S3 storage and requests, CloudFront transfer at $0.09 per GB after 1 TB, RDS instance hours and storage, NAT gateway hours and data, public IPv4 addresses. The first bill teaches you which ones you forgot.

Managed databases have their own meters. Neon and Supabase bill by storage and compute hours. PlanetScale by rows read and written. Turso by rows and storage. Railway Postgres by the resources the container uses.

Step 3: multiply

Now put the table from step 1 against the meters from step 2. Here is our sample app on four hosts. I round and I ignore taxes.

100 DAU1,000 DAU10,000 DAU100,000 DAU
Cloudflare Workers$0$0~$10~$90
Vercel (commercial)$20$20~$95~$2,100
Hetzner VPS€5€5€5–16€16–40 + your time
Railway~$5~$5–10~$20–40~$100+

How I got there:

Cloudflare. 1.5 million requests a month is under the free plan’s 3 million. At 10,000 DAU: $5 plan, 15 million requests minus 10 million included is 5 million × $0.30 = $1.50. CPU: 225 million ms minus 30 million included is 195 million × $0.02 = $3.90. Total about $10. At 100,000 DAU the same math gives $5 + $42 + $44, about $90. Egress, 15 TB, costs nothing.

Vercel. The Hobby plan is not allowed for commercial use, so the floor is $20 from day one. At 1,000 DAU, 150 GB fits in Pro’s 1 TB. At 10,000 DAU, 1.5 TB is 500 GB over: 500 × $0.15 = $75, plus $20 is $95. At 100,000 DAU, 15 TB is 14 TB over: 14,000 × $0.15 = $2,100. Function duration adds more on top. Data transfer alone explains the number.

Hetzner. One small server handles the first three columns, and 15 TB is inside the 20 TB allowance. At 100,000 DAU you probably need a bigger server or two servers behind a load balancer. Call it €16–40. The number that does not appear in the table is your evenings.

Railway. Usage billing for a small always-on Node service with Postgres. The estimate is rougher because it depends on how much memory your app holds. Set a spending limit.

The lesson is not “Cloudflare is cheapest”. It is that the same app has a 200× price spread between hosts at 100,000 users, and the spread is decided by one meter: egress. If your app serves small JSON responses instead of 100 KB pages, Vercel’s column collapses and the comparison changes.

Run the numbers for your app, not mine.

Where bills jump

Bills don’t grow smoothly. They step. These are the steps I check for on any platform.

The free tier has a hard limit. Above it you are not billed for overage, you are moved to a paid plan. Cloudflare’s free plan stops at 100,000 requests a day. Netlify’s stops when the credits run out. The step is from $0 to the plan floor.

Plan floors and seats. Vercel and Netlify cost $19–20 per seat before you serve a byte. Add a collaborator, double the floor. This is the cliff for small teams, not for traffic.

Egress. The most expensive meter on Vercel, Netlify, AWS, Supabase. Free on Cloudflare, nearly free on Hetzner. A site with images and downloads should be priced on this line first.

Database writes. D1 charges $1 per million writes and $0.01 per million reads. A hundred times more. An app that logs every page view to the database pays for it. PlanetScale’s row-based billing has the same shape. Batch writes, or send the logs somewhere cheaper.

The second instance. Always-on platforms jump when one server is no longer enough. On Render, Fly or a VPS, you go from $7 to $14, or from €5 to €16 plus a load balancer. There is no smooth line between.

Multi-region. On Fly.io, every extra region is another copy of your Machine. Add regions when latency data says you need them, not because the map looks cool.

Overage rounding. Overage is billed in chunks. One request over a million-request boundary costs a full million’s worth. Small at Cloudflare’s prices, painful at AWS’s.

The AWS extras. NAT gateways at $32 a month plus data. Public IPv4 addresses at $3.60 each. Cross-availability-zone transfer. Forgotten EBS volumes. None of these appear in a “Lambda + RDS” estimate.

Usage that grows without users. Railway bills memory by the second. A memory leak is a bill. An idle staging environment is a bill. A cron job that runs every minute is a bill.

Predictable or elastic?

After running the numbers, you face one more choice.

A flat-price host (VPS, Render, Fly) costs the same every month. You know the bill. When traffic doubles, you upgrade by hand. If a bot hammers your API, you get slow, not poor.

A usage-based host (Cloudflare, Vercel, Railway, Cloud Run) costs almost nothing when you are small and grows with you. You never upgrade. If a bot hammers your API, you get a bill.

Neither is wrong. Pick by your tolerance. If a surprise $500 invoice would hurt, take the flat price, or cap the usage-based host on day one. Vercel and Railway let you set a hard spending limit. Cloudflare and Netlify give you billing alerts. Turn them on before you deploy, and set the alert at half of what you are willing to pay.

How I priced my own projects

This blog is static, about 1,900 posts and thousands of images. I host it on Cloudflare Pages because egress is free. On Vercel or Netlify the bandwidth would be the entire bill.

I learned the metering lesson the hard way on the same site. In summer 2026 I added a Pages Function to serve Markdown to AI agents based on the Accept header. A root-level function on Pages routes every request through the Worker, including every image and CSS file. A static site that cost nothing was suddenly a metered Worker invocation per asset. I removed it and now generate static .md files at build time instead. Same feature, zero invocations. I wrote about the final approach in Serving Markdown to AI agents.

StackPlan runs on Cloudflare Workers with D1. Before building it I did the D1 math above. The write price is why it caches LLM responses in KV and why I avoided writing to D1 on every request.

My analytics is a self-hosted Plausible on a VPS. Flat price. I chose that over per-pageview pricing because pageviews are the one meter I can’t control: a viral post would have cost me money on a hosted plan. On my server it costs me nothing extra.

For pricing data itself, I keep the numbers in files with a checked-on date and version them, because provider prices change under you. I described that in Versioning reference data with effective_from dates.

The method, in short

  1. Write down your assumptions: requests per user per day, KB per request, reads and writes per request.
  2. Multiply by daily active users and 30 days, at 100, 1k, 10k and 100k.
  3. List the meters each candidate host bills on. Egress first.
  4. Price each column. Note where the number steps, not just where it grows.
  5. Decide flat or elastic, and set a spending limit before deploying.

StackPlan does these steps for you: you describe the app, it produces the stack and the four-column forecast, with the cost cliffs marked. The first recommendation is free, the alternatives are behind a $20 a month plan. But you can do all of this with the table above and a calculator. That is the point of this post.

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about platform: