40 Hours of Free SQL: Picking a Database on Cloudflare vs Azure as a Solo Founder
In my last post I priced the same small project on Cloudflare and Azure, round by round. Azure won the database round in four sentences: deeper toolbox, real PostgreSQL and SQL Server, decades of enterprise tooling.
That's true. But four sentences is too short for the one decision that's hardest to undo.
You can move a static site between hosts in an afternoon. You can rewrite a serverless function in a weekend. Your database, on the other hand, holds the schema, the queries, the data and every habit your code formed around them. Whatever you pick in week one is usually what you're still running in year two.
So this time I asked a narrower question, the one a solo founder actually faces:
I need to ship this month. Which database gets me there fastest, costs nothing until it should, and won't trap me later?
All prices are public list prices in US dollars, checked in October 2026, for US regions (Azure East US). Cloud pricing changes often, so check before you plan a budget around it.
The menu
Neither platform offers "a database". Each offers a shelf.
| Need | Cloudflare | Azure |
|---|---|---|
| Relational, serverless | D1 (SQLite) | Azure SQL Database, serverless tier (SQL Server) |
| Real PostgreSQL / MySQL | Hyperdrive in front of any Postgres or MySQL, incl. PlanetScale billed through Cloudflare | Azure Database for PostgreSQL / MySQL, Flexible Server |
| Document / NoSQL | — | Cosmos DB |
| Key-value | Workers KV | Table Storage, Cosmos DB |
| Per-user or per-room state | Durable Objects (each with its own SQLite) | — |
The headline difference: Cloudflare doesn't run a Postgres server for you. Its relational answer is SQLite (D1), and for anything bigger it gives you a fast pipe (Hyperdrive) to a Postgres that lives somewhere else. Azure runs everything itself.
For the rest of this post I'll mostly compare the four options a solo founder is likely to start with: D1, Azure SQL Database, Cosmos DB and Azure PostgreSQL Flexible Server.
Round 1: Time to first query
This is where "start quickly" is won or lost.
Cloudflare D1 is three steps, and none of them involves a password:
npx wrangler d1 create app-db
// wrangler.jsonc
"d1_databases": [
{ "binding": "DB", "database_name": "app-db", "database_id": "<id from the command above>" }
]
const user = await env.DB
.prepare("SELECT * FROM users WHERE email = ?")
.bind(email)
.first();
No connection string, no firewall rule, no secret to rotate, no connection pool to size. wrangler dev gives you a local copy for development, and wrangler d1 migrations handles schema changes. The database is a binding, not a network endpoint you have to defend.
The catch: D1 is built to be used from Workers. You can reach it from elsewhere over an HTTP API, but if your backend lives on another platform, most of this convenience disappears.
Azure SQL Database isn't hard, but it's a longer list of decisions:
- A resource group.
- A logical server, with an admin login or Microsoft Entra authentication.
- A firewall rule (your IP, plus "allow Azure services" for your app).
- A connection string, stored in app settings or Key Vault.
- A driver (
mssqlfor Node, or EF Core for .NET). - Retry logic. Serverless databases pause when idle, and Microsoft's own docs say the first connection after a pause produces predictable transient errors. You must handle them.
PostgreSQL Flexible Server is the same shape, plus a networking choice (public access or a private VNet) that you make up front. Cosmos DB asks you to choose a partition key before you write your first document, which is easy to get wrong when you don't know your access patterns yet.
None of this is unreasonable. It's what running a real database server looks like. But on day one, it's an afternoon on Azure versus ten minutes on Cloudflare.
Winner: Cloudflare, as long as your code runs on Workers.
Round 2: What does "free" actually buy?
Both platforms advertise free databases. They mean very different things.
| Cloudflare D1 | Azure SQL free offer | Cosmos DB free tier | Azure PostgreSQL (free account) | |
|---|---|---|---|---|
| How long | Forever | Forever | Forever | 12 months |
| What's free | 5M rows read + 100K rows written per day, 5 GB total | 100,000 vCore-seconds + 32 GB per database per month, up to 10 databases | 1,000 RU/s + 25 GB, always on | 750 hours of a B1ms server + 32 GB |
| Size limit | 500 MB per database (10 GB on paid) | 32 GB | 25 GB free, then billed | 32 GB free, then billed |
| When you run out | Queries fail until 00:00 UTC | Database pauses until next month, or you opt in to paying | Billed at normal rates | Billed at normal rates |
| Catch | Rows scanned count, not rows returned | See below | One per subscription, opt in at creation only | Ends after a year |
The row that surprised me is the Azure SQL one. Let's do the math.
The free SQL database that lasts 40 hours
The Azure SQL free offer gives each database 100,000 vCore-seconds of serverless compute per month. That sounds like a lot until you read how serverless is billed.
While the database is online, Azure bills the maximum of CPU used, memory used, and the minimum you configured, every second. With the default minimum of 0.5 vCores, the matching minimum memory (about 2.1 GB) normalizes to about 0.7 vCores. So an online database costs at least 0.7 vCore-seconds per second, even if it's doing nothing.
100,000 vCore-seconds ÷ 0.7 ≈ 143,000 seconds ≈ 40 hours
Forty hours of being awake per month. It only pauses after it's been idle for the auto-pause delay: 60 minutes by default, 15 at minimum. So:
- If anything touches the database at least every 15 minutes (an uptime monitor, a cron job, a search crawler hitting a page that runs a query), it never pauses. The month's allowance is gone in under two days.
- If traffic comes in bursts, each wake-up costs at least the auto-pause delay: about 40 wake-ups a month at the 60-minute default, or about 160 at 15 minutes.
When the allowance runs out, the default is to pause the database until the first of next month. For a production app, that's an outage. The alternative is to keep it online at serverless rates: $0.000145 per vCore-second, which works out to about $250 a month for a database that's always awake at the minimum size.
To be fair, this offer is excellent for what it's designed for: development, staging, demos and internal tools that sit idle most of the time. It's just not a free production database for an app with steady traffic. If you want cheap Azure SQL in production, the old DTU Basic tier (about $5 a month for a 2 GB database) is the honest option. It's small, but it doesn't pause.
The D1 catch: rows scanned, not rows returned
D1 bills rows read, and that means rows scanned. A query that filters on an unindexed column and returns one row out of 50,000 is billed for 50,000.
Run that query 100 times and you've used the whole free plan's daily 5M reads. Add the index and the same query reads a handful of rows. Every D1 result includes meta.rows_read, so log it early and you'll catch this in development, not on your bill.
The other D1 limit to know before you start: 10 GB per database, hard cap, even on the paid plan. D1 is designed for many small databases (one per customer, for instance), not one big one.
The quiet winner: Cosmos DB's free tier
Cosmos DB's free tier is the most generous "always on" free database here: 1,000 RU/s of provisioned throughput and 25 GB, for the life of the account. It never pauses and never runs out mid-month. As a rough guide, a point read of a 1 KB document costs 1 RU, so that's a lot of headroom for a small app.
The catches are real, though. You get one free-tier account per subscription, you must turn it on when you create the account, it doesn't work with the serverless option, and Cosmos DB is a document database with a proprietary query model. If you think in tables and joins, you'll fight it.
Winner: Cloudflare D1 for a free production database. Cosmos DB if you want NoSQL. Azure SQL's free offer is for dev and staging.
Round 3: The first real bill
Free tiers end. Here is roughly what the first paid month looks like for a small app with a couple of gigabytes of data and steady traffic throughout the day:
| Option | Rough monthly cost | What you get |
|---|---|---|
| Cloudflare D1 | $5 | Workers Paid: 25B rows read, 50M rows written, 5 GB included. The same $5 also covers your Workers. |
| PlanetScale Postgres via Hyperdrive | ~$5 | A single-node Postgres, billable on your Cloudflare invoice. Hyperdrive queries are unlimited on Workers Paid. |
| Cosmos DB free tier | $0 | As long as you stay within 1,000 RU/s and 25 GB. |
| Azure SQL, DTU Basic | ~$5 | 5 DTUs and 2 GB. Small, predictable, always on. |
| Azure PostgreSQL B1ms | ~$12 + storage | After the first free year. 1 vCPU, 2 GB RAM, real Postgres. |
| Azure SQL serverless, always awake | ~$250 | What the free offer becomes if you choose "continue with charges" and it never pauses. |
The pattern from my last post shows up again:
- Cloudflare bills work. Rows read, rows written, gigabytes stored. An idle database costs nothing, and a busy one costs fractions of a cent per million rows.
- Azure bills time and capacity. vCore-seconds while the database is awake, hours a server runs, RU/s you provision. A database that's always reachable is a database that's always billing.
Neither is wrong. But for a project that might get ten visitors a day or ten thousand, billing by work is far kinder.
Winner: Cloudflare, with Cosmos DB's free tier as a strong exception.
Round 4: The ceiling, and the way out
Starting quickly is only half the decision. The other half is what happens when you outgrow it, or need to leave.
D1 is SQLite. That's both its limit and its escape hatch. wrangler d1 export gives you a plain .sql file you can load into any SQLite, and with some dialect fixes into Postgres. But the 10 GB per-database cap is real, and each database processes queries one at a time. With 1 ms queries that's about 1,000 per second, which is plenty for most indie apps, but it is a ceiling.
Azure PostgreSQL is the most portable choice on this list. Postgres runs everywhere, every ORM supports it, and moving it later is a pg_dump away.
Azure SQL is SQL Server. That's very portable within the Microsoft world, and great if you live in .NET and EF Core, but less so anywhere else.
Cosmos DB has the most lock-in. Its native API exists nowhere else. The MongoDB-compatible API helps, but it's still a migration.
And here's the part that took me longest to notice: the platforms don't have to match. Cloudflare's Hyperdrive will happily sit in front of a Postgres running on Azure. Workers at the edge plus Azure Postgres behind them is a perfectly sensible architecture. You can start on D1, and if you hit the ceiling, move the data to Postgres without moving your app off Workers.
Winner: Azure PostgreSQL for portability. D1 as long as you stay under its ceiling.
Round 5: When you break something
Every solo founder eventually runs DELETE without a WHERE.
- D1 Time Travel is always on and free: restore to any minute in the last 30 days on the paid plan, 7 on free. No setup, no extra cost.
- Azure SQL and PostgreSQL Flexible Server both have automatic backups with point-in-time restore. The Azure SQL free offer limits it to 7 days.
- Cosmos DB takes periodic backups by default. Continuous backup, with point-in-time restore, is an option you choose.
All of them will save you. D1 makes it the easiest, because there's nothing to configure in advance.
Winner: Cloudflare, narrowly.
The scorecard
| Round | Winner |
|---|---|
| Time to first query | Cloudflare (on Workers) |
| What "free" buys | Cloudflare D1 / Cosmos DB free tier |
| The first real bill | Cloudflare |
| Ceiling and portability | Azure PostgreSQL |
| Recovery | Cloudflare, narrowly |
My short version
If I were starting a new project tomorrow:
-
My app runs on Workers and the data is relational: D1. Index everything I filter on, and log
rows_readfrom day one. - I need real Postgres (extensions, an ORM that expects it, or data that will clearly exceed 10 GB): Postgres from the start, either Azure Flexible Server or PlanetScale through Hyperdrive.
- I'm already deep in .NET and Azure: Azure SQL, but on the Basic or provisioned tier for production. Keep the free offer for staging.
- My data really is documents and my throughput is predictable: Cosmos DB with the free tier switched on at creation.
- I'm unsure: D1. It's the cheapest to try and the easiest to export from. Moving SQLite to Postgres later is a weekend; moving off a document store is a project.
Or, in one line:
Azure's free databases give you time. Cloudflare's give you work. For a solo founder with unpredictable traffic, work is the better deal.
Where this is going
I have two projects to decide on:
Media tools for creators and What to do in your city
Both will need a database eventually. Accounts, saved favorites, reviews, a creator's presets synced across devices: the moment one of those features ships, this post stops being research and becomes a decision.
When that happens, I'll write up which one I picked and whether the numbers above survived contact with real users.
Until then: what are you running, and what surprised you on your first real bill? I'd love to hear it in the comments, especially if you've hit the D1 ceiling or the Azure SQL free limit in production.
Top comments (0)