# $870/mo for Zero Users: How to Choose a Deployment Platform

A client paid $870 a month on Azure for a product with zero users; the same workload runs on Cloudflare for $10. When Vercel, Cloudflare, Railway, a VPS, or a hyperscaler is the right call: by product stage, egress, and the cost of leaving.

**Published:** August 15, 2026
**Category:** Software Development
**Tags:** Infrastructure, Cloud Costs, Web Development

![$870/mo for Zero Users: How to Choose a Deployment Platform](/blog/deployment-platform-choice/bill.png)

---

This year I audited a pre-launch marketplace with zero users and an Azure bill of $870 a month. I modeled the same workload on Cloudflare and got $10. Someone picked enterprise defaults before the product had users, and nobody looked at the invoice again.

The client was two business partners who hired an agency to build a booking marketplace, technically an Airbnb, with listings, reservations, payments and three kinds of users. They knew technology well and had built their own sites with AI coding tools, but they weren't infrastructure engineers. So the invoice arrived every month and they assumed that's what infrastructure costs. It isn't. About [29% of cloud spend is waste](https://www.flexera.com/about-us/press-center/flexera-finds-cloud-value-is-rising-while-ai-waste-grows) across the industry, and pre-launch products are the worst case, paying an always-on price for traffic that doesn't exist yet.

Their audit runs through this post, and what picks a platform is the same everywhere: your product stage, how much data you serve out, and what it costs to leave later.

## Where $870 a month goes with zero users

I rebuilt the bill from the invoice and the codebase:

| Line | $/mo at 0 users |
|---|---|
| Container compute (8 always-on containers across prod + staging) | $726 |
| Managed PostgreSQL (2 environments) | $32 |
| Managed Redis (2 environments) | $32 |
| Load balancer | $36 |
| Private network endpoints | $44 |
| Storage and traffic | ~$0 |

A container is a rented computer that bills 24 hours a day whether anyone visits or not. This app ran eight of them, four services duplicated across production and staging, and that line alone is $726 of the $870.

The load balancer charges about $18 per environment just to exist, so $36 a month routes zero traffic. The private endpoints buy a sealed-off internal network, a compliance feature, for an app with no compliance requirement. Staging is roughly half of everything, because the whole always-on fleet is duplicated per environment.

Azure's container platform can scale to zero when configured for it. Nobody configured it. The audit found no CI pipeline, no release process, and two incompatible deploy configurations sitting in the same repository. The agency picked enterprise defaults, shipped, and moved on.

## The same product for $10

Usage billing, usually called serverless, runs your code per request and bills per request, so with no users you're paying a small base fee. I mapped the product onto Cloudflare's stack:

| On Azure | On Cloudflare |
|---|---|
| 3 frontend containers + 1 API container | One Next.js app on Workers\* |
| Blob file storage | R2 storage |
| Managed PostgreSQL | PlanetScale Postgres ($5 plan) |
| Redis cache | Workers KV |
| WebSocket chat via Redis | Durable Objects |
| Load balancer, private network | Included. Cloudflare balances the traffic itself, and Tunnels cover private networking if you ever need it |

\* Next.js because that's what the product was built in. A lighter full-stack framework like [TanStack Start](https://tanstack.com/start) covers the same needs (routing, server rendering, data loading) with less server work per request, and on usage billing less compute is less money. I haven't benchmarked it on this workload, but for a greenfield app on Workers it's worth evaluating.

I held the load assumptions the same on both sides, across the growth curve:

| Monthly active users | Azure | Cloudflare |
|---|---|---|
| 0 (pre-launch) | $870 | $10 |
| 1,000 | $936 | $36 |
| 10,000 | $1,248 | $62 |
| 100,000 | $2,375 | $252 |
| 500,000 | $7,452 | $1,039 |

There's no crossover where Azure gets cheaper.

The gap narrows as both stacks converge on database and bandwidth costs at scale, but it never closes. Egress is the data your app sends out, every listing photo and every page. Azure charges $0.087 per GB after the first 100 GB each month. Cloudflare's R2 charges zero, permanently, as policy. For this photo-heavy marketplace that line grows from $0 to $2,115 a month across the curve, and at the top tier Azure's egress alone exceeds the entire Cloudflare bill. You can negotiate a unit price down. Zero is a different business model, so there's nothing to negotiate against.

These are list prices, and the load numbers are modeled rather than measured, with nothing in them for the migration itself. The frontends, the file storage and the database move cleanly; the realtime chat has to be rebuilt on Durable Objects, and that's the real work. The client hasn't migrated yet, and my own call would be to do it now, while the product is still small: $860 a month is $10,000 a year, and AI agents have made this kind of port far cheaper than it used to be, which I come back to below.

## Four questions that pick your platform

**Is your traffic bursty or flat?** Early products are bursty by definition, with spikes around launches and silence between. Bursty and low means usage billing (Cloudflare, Vercel), where the floor is near zero. Once load goes flat, predictable and high, per-hour billing catches up and a plain rented server becomes the cheapest option of all.

**How much data do you serve out?** If you serve photos, video or downloads, put media on zero-egress storage (R2, Bunny) before you touch anything else. That one decision can outweigh every other line on the bill.

**Does anything run long or hold state?** Background jobs, WebSockets, video processing, anything that keeps a process or a file open. Serverless makes you rearchitect all of it, and that rewrite is what serverless costs you. With a lot of it, containers fit, so look at Railway, Fly or a VPS.

**Who operates it at 3am?** A server you manage yourself costs someone's time, less of it than it used to now that agents do the setup, but the pager still rings at a person. If nobody on the team will answer it, take the managed platform.

Region lists, free-tier sizes and benchmark charts are rounding errors next to these four.

## The platforms

**Vercel** costs $20 a month with 1 TB of bandwidth included, then $0.15 per GB. You're buying speed, with zero configuration for Next.js and a preview deployment on every pull request, and you pay for that speed at scale, where the bill gets expensive and hard to predict. Take it from zero to product-market fit, and for marketing sites, where shipping fast is worth more than the infra bill. My own products all run between free and $5 a month across Vercel and Cloudflare.

**Cloudflare** has the cheapest floor. Workers costs $5 a month, storage runs $0.015 per GB, egress is zero, and quotas pool across your whole account, so a staging environment costs almost nothing extra. You pay by building to its runtime. Workers is not Node, and Durable Objects are a programming model you have to learn. Best fit for greenfield products, media-heavy products, and global read-heavy traffic.

**Railway, Render and Fly** sit in the middle, with containers on usage billing and no Kubernetes. Railway charges $20 per vCPU and $10 per GB of RAM per month on a $5 plan floor. That's where an existing Dockerfile lands, along with background workers and cron jobs. For the audited client, lifting their four containers here would have cut the bill hard with no rewrite at all, so Cloudflare was the best number available and never the only exit.

**A VPS plus a CDN** is the cheapest compute per dollar by a wide margin. A Hetzner server with 4 GB of RAM runs about €5.50 a month, a DigitalOcean one starts at $4. You own updates, backups, TLS and the pager, and you put a CDN in front (Bunny charges about $0.01 per GB) for latency and egress. It's the fit for steady load, background-heavy work, and a team willing to own the machine. My own setup is written up in [How I Set Up a VPS with Claude Code](/blog/claude-code-vps-setup).

**The hyperscalers** (AWS, Azure, GCP) win on compliance regimes, enterprise agreements, large credits, and managed services that exist nowhere else. Azure was a fine vendor for the audited client and a bad fit, enterprise infrastructure sized for a stage the product hadn't reached and then left running with no owner.

## Renting the whole machine

Between a $5 VPS and a hyperscaler sits a step most people skip, which is renting a whole physical machine from the company that owns the rack. A Hetzner AX42 is an 8-core Ryzen with 64 GB of ECC memory and two NVMe drives for about [€57 a month](https://www.hetzner.com/dedicated-rootserver/matrix-ax/) with unmetered traffic, and OVH sells the same shape of thing. You get the entire CPU instead of a slice of one, and the price is identical every month whatever your traffic does.

Say the client rents that box and, for the sake of argument, rents an NVIDIA DGX Spark next to it, to run Qwen3.8 27B for no reason. [Enverge](https://spark.enverge.ai/) rents one at $0.75 an hour, so every hour of the month is $548, and the server underneath is under $70. The pair comes to about $620 against Azure's $870.

What you give up is elasticity, because a rented machine has a fixed ceiling and a launch spike lands on hardware that can't grow in the next ten minutes. You plan for that yourself, with a CDN in front, a queue behind the slow paths, and a second box you can switch on. You also own the operating system, the patches, the backups and the pager, and hardware does fail.

The ops half of that got cheaper, since setting up a firewall, a reverse proxy, TLS renewal, backups and monitoring used to be a weekend for someone who knew what they were doing, and an agent with SSH access now does it in an afternoon and reads the logs when something breaks. A VPS is the right rung while the product is small and changing. Move up to a rented machine once load goes flat and the bill stops moving with it.

## Before you pay a hyperscaler, ask for credits

At the early stage the big clouds will often host you for free. You've just got to ask.

Every hyperscaler runs a startup program (AWS Activate, Microsoft for Startups, Google for Startups) that hands out credits to early products, and it works informally too. My brother [Kirill](https://kirill-markin.com/) runs an [open-source flashcards app](https://flashcards-open-source-app.com/) on AWS. At some point AWS emailed him, unprompted, offering monthly credits that cover his whole infrastructure, so he hosts for free. When the first six months ran out, his AWS contact told him to reapply while the product was still early, and they'd grant another round. It's a cheap bet for them. A product that turns into a business is a paying customer already built on their platform.

So write to the provider's startup team, describe the product and the stage, and ask. You'll usually get six months to a year of free hosting, renewable while you stay small.

Credits change the bill and nothing else. When they run out you're back at list price, on the platform your code is now shaped for.

## Lock-in lives in your code

Lock-in sounds like a contracts problem. It's mostly a code problem: how much of your codebase is written against one vendor's way of working, and what the rewrite costs when you leave.

A Dockerfile runs anywhere, so containers and a VPS are the portable end. Vercel is mild, since you can deploy a standard Next.js app elsewhere with some work. Cloudflare is the deep end, where Workers code targets a non-Node runtime and anything built on Durable Objects is structured around them. Storage is the exception, because R2 speaks the S3 API, so moving files off it is a credentials change rather than a rewrite. An escape hatch is forming for the harder half too: Deno's [celld](https://github.com/denoland/celld) runs Durable-Object-style objects on your own machines, each one its own SQLite database. It's a young project and not API-compatible with Cloudflare, so treat it as a direction rather than somewhere to put production realtime today.

Tooling softens part of this: [Alchemy](https://alchemy.run/) defines Cloudflare or AWS infrastructure in plain TypeScript instead of Terraform, so you escape the tooling lock-in and keep infrastructure in the same language as the app. You still can't move to another cloud without rewriting the Worker itself.

The exit price is falling too, because AI coding agents got good at this kind of work. Give an agent a deployment that runs and infrastructure defined in code and it's got a testing ground. It can run the existing system, watch how each piece behaves (a chat room, an upload flow), and rebuild it on the new platform against those observations. Even Durable Objects translate this way. Bun was [rewritten from Zig to Rust by AI agents](https://bun.com/blog/bun-in-rust) in 11 days, over a million lines, with all 60,000 tests kept passing, for $165,000 of compute at API list price. That's runtime-rewrite scale. An app migration sits far below it, and moving this client's chat layer between Durable Objects and Redis, in either direction, is about a week of agent work on a $200-a-month plan.

So accept lock-in only where it pays you. R2's zero egress is worth being tied to, and so are Durable Objects when realtime is your core product. Everywhere else, plain HTTP boundaries and an ORM keep the exits open.

## The database version of the same story

The partners suggested Supabase to their developers, the developers answered that it wouldn't scale, and they were right. Then both sides defaulted back to expensive managed databases on Azure, because neither knew the middle of the market existed.

Supabase bundles authentication wired directly into the database, realtime updates, file storage and a free tier that gives any account two live projects, and it's Postgres underneath, so you can leave. For prototypes, demos and side projects, that free tier is the best offer in this market. What I wouldn't do is run a production database on it. Connections route through a shared pooler and the lower tiers run on shared CPU, so tail latency swings under load ([one reported case](https://github.com/orgs/supabase/discussions/28141)), free projects pause after a week of inactivity, and Supabase's own platform maintenance takes pieces of the stack down often enough that I've stopped reading the status banner on my dashboard. That's a prototyping platform, and the mistake is reaching for it a stage later.

PlanetScale starts at $5 a month for Postgres, and its Metal tier puts the database on drives attached directly to the machine instead of network storage, which moves disk latency from milliseconds to microseconds. Their [published benchmarks](https://planetscale.com/benchmarks) against Supabase, Neon and Aurora are vendor benchmarks, though reproducible ones with the method open, and I've got nothing to gain from either company. Any vendor in this tier could make the same case, and the case is that a $5 to $50 managed database can outperform the "safe" $100-plus cloud database an enterprise default reaches for.

A library like [Drizzle](https://orm.drizzle.team/) owns your schema and migrations in code, and with one in place, swapping between Postgres providers is close to a connection-string change. Start on a $5 Postgres and move up when the product earns load or funding, without touching application code. That holds between providers of the same database. Switching database engines stays expensive.

## You are not Facebook

The standard defense of the big setup is future scale, building it right so it survives success. But Cloudflare, the toy option in that argument, fronts [more than 20% of the web](https://blog.cloudflare.com/500-tbps-of-capacity/) and 24% of all websites by [W3Techs' count](https://w3techs.com/technologies/overview/proxy). Infrastructure serving a quarter of the internet will serve your marketplace. And the scale you're building for rarely arrives: most products never pass 10,000 monthly users, which is the $62 row in that table.

The logic runs the other way at the top. 37signals left AWS with a $3.2 million yearly bill and [saves about $2 million a year](https://world.hey.com/dhh/our-cloud-exit-savings-will-now-top-ten-million-over-five-years-c7d9b5bd) running their own hardware, because at flat, predictable, massive load, owning compute wins. Buying the machines is a further rung than renting them, and the mistake in both directions is identical: paying for a stage you aren't at. Oz Nova made this argument in [You Are Not Google](https://blog.bradfieldcs.com/you-are-not-google-84912cf44afb) back in 2017.

## Match the platform to the stage

| Stage | What it looks like | What fits |
|---|---|---|
| Prototype / pre-launch | Zero users, product changes daily | Vercel or Cloudflare; the monthly floor should be near zero |
| Early product | First paying users, bursty traffic | Vercel or Cloudflare; Railway if you have background workers |
| Growing, media-heavy | Bandwidth appears on the bill | Move files to zero-egress storage first, before touching compute |
| Steady and predictable | Flat load, known shape | VPS or a rented dedicated machine plus CDN, or containers on Railway or Fly |
| Compliance / enterprise | Audits, procurement, data residency | Hyperscaler, chosen deliberately, with an owner |

For the audited client the recommendation was the Cloudflare column, $860 a month back, roughly $10,000 a year, weighed against weeks of migration work. They've got the numbers now.

Price the stage you're at instead of the one in the pitch deck, read the egress line before the compute line, and price the exit before you enter.

A bill that nobody owns is wrong, whatever the vendor.

---

## Links

- Blog post: https://andrey-markin.com/blog/deployment-platform-choice
- All blog posts: https://andrey-markin.com/blog
- Contact: https://andrey-markin.com/#contact
