I run multiple $10K MRR companies on a $20/month tech stack

https://stevehanov.ca/blog/how-i-run-multiple-10k-mrr-companies-on-a-20month-tech-stack

How I run multiple $10K MRR companies on a $20/month tech stack

Steve Hanov's Blog

> The enterprise mindset dictates that you need an out-of-process database server. But the truth is, a local SQLite file communicating over the C-interface or memory is orders of magnitude faster than making a TCP network hop to a remote Postgres server.

I don't want to diss SQLite because it is awesome and more than adequate for many/most web apps but you can connect to Postgres (or any DB really) on localhost over a Unix domain socket and avoid nearly all of the overhead.

It's not much harder to use than SQLite, you get all of the Postgres features, it's easier to run reports or whatever on the live db from a different box, and much easier if it comes time to setup a read replica, HA, or run the DB on a different box from the app.

I don't think running Postgres on the same box as your app is the same class of optimistic over provisioning as setting up a kubernetes cluster.

> It's not much harder to use than SQLite, you get all of the Postgres features, it's easier to run reports or whatever on the live db from a different box, and much easier if it comes time to setup a read replica, HA, or run the DB on a different box from the app.

Isn't this idea to spend a bit more effort and overhead to get YAGNI features exactly what TFA argues against?

Looks like the overhead is not insignificant:

Running 100,000 `SELECT 1` queries:
PostgreSQL (localhost): 2.77 seconds
SQLite (in-memory): 0.07 seconds

(https://gist.github.com/leifkb/1ad16a741fd061216f074aedf1eca...)

gist:1ad16a741fd061216f074aedf1ecaf62

GitHub Gist: instantly share code, notes, and snippets.

Gist
This is mostly about thread communication. With SQLite you can guarantee no context switching. Postgres running on the same box gets you close but not all the way. It's still in a different process.
This. Run anything on the same box as PG and you can easily be plagued by out of memory etc (as theres memory contention between the two processes).
I love them both too but that might not be the best metric unless you’re planning to run lots of little read queries. If you’re doing CRUD, simulating that workflow may favor Postgres given the transactional read/write work that needs to take place across multiple concurrent connections.

> I love them both too but that might not be the best metric unless you’re planning to run lots of little read queries.

Exactly. Back in the real world,anyone who is faced with that sort of usecase will simply add memory cache and not bother with the persistence layer.

Most important is that that local SQLite gets proper backups, so a restore goes without issues
Gets proper backups if you back it up the right way https://sqlite.org/backup.html
SQLite Backup API

Would be nice to see PGLite[1] compared too

1: https://pglite.dev/

PGlite

Lightweight WASM Postgres

A total performance delta of <3s on ~300k transactions is indeed the definition of irrelevant.

Also:

> PostgreSQL (localhost): (.
.) SQLite (in-memory):

This is a rather silly example. What do you expect to happen to your data when your node restarts?

Your example makes as much sense as comparing Valkey with Postgres and proceed to proclaim that the performance difference is not insignificant.

I have used SQLite with extensions in extreme throughput scenarios. We’re talking running through it millions of documents per second in order to do disambiguation.
I won’t say this wouldn’t have been possible with a remote server, but it would have been a significant technical challenge.
Instead we packed up the database on S3, and each instance got a fresh copy and hammered away at the task. SQLite is the time tested alternative for when you need performance, not features

I've been doing that for decades.. People seem to simply not know about unix architecture.

What I like about sqlite is that it's simply one file

Sqlite smokes postgres on the same machine even with domain sockets [1]. This is before you get into using multiple sqlite database.

What features postgres offers over sqlite in the context of running on a single machine with a monolithic app? Application functions [2] means you can extend it however you need with the same language you use to build your application. It also has a much better backup and replication story thanks to litestream [3].

- [1] https://andersmurphy.com/2025/12/02/100000-tps-over-a-billio...

- [2] https://sqlite.org/appfunc.html

- [3] https://litestream.io/

The main problem with sqlite is the defaults are not great and you should really use it with separate read and write connections where the application manages the write queue rather than letting sqlite handle it.

100000 TPS over a billion rows: the unreasonable effectiveness of SQLite

A blog mostly about Clojure programming

> Sqlite smokes postgres on the same machine even with domain sockets [1].

SQLite on the same machine is akin to calling fwrite. That's fine. This is also a system constraint as it forces a one-database-per-instance design, with no data shared across nodes. This is fine if you're putting together a site for your neighborhood's mom and pop shop, but once you need to handle a request baseline beyond a few hundreds TPS and you need to serve traffic beyond your local region then you have no alternative other than to have more than one instance of your service running in parallel. You can continue to shoehorn your one-database-per-service pattern onto the design, but you're now compelled to find "clever" strategies to sync state across nodes.

Those who know better to not do "clever" simply slap a Postgres node and call it a day.

I wonder what percentage of services run on the Internet exceed a few hundred transactions per second.
I think the better question to ask is what services peak at a few hundred transactions per second?

> SQLite on the same machine is akin to calling fwrite.

Actually 35% faster than fwrite [1].

> This is also a system constraint as it forces a one-database-per-instance design

You can scale incredibly far on a single node and have much better up time than github or anthropic. At this rate maybe even AWS/cloudflare.

> you need to serve traffic beyond your local region

Postgres still has a single node that can write. So most of the time you end up region sharding anyway. Sharding SQLite is straight forward.

> This is fine if you're putting together a site for your neighborhood's mom and pop shop, but once you need to handle a request baseline beyond a few hundreds TPS

It's actually pretty good for running a real time multiplayer app with a billion datapoints on a 5$ VPS [2]. There's nothing clever going on here, all the state is on the server and the backend is fast.

> but you're now compelled to find "clever" strategies to sync state across nodes.

That's the neat part you don't. Because, for most things that are not uplink limited (being a CDN, Netflix, Dropbox) a single node is all you need.

- [1] https://sqlite.org/fasterthanfs.html

- [2] https://checkboxes.andersmurphy.com

35% Faster Than The Filesystem

There are zero reasons to limit yourself to 1GB of RAM. By paying $20 instead of $5 you can get at least 8gb of RAM. You can use it for caches or a database that supports concurrent writes. The $15 difference won’t make any financial difference if you are trying to run a small business.

Thinking about on how to fit everything on a $5 VPS does not help your business.

$15 is not exactly zero, is it? If you don't need more than 1GB, why pay anything for more than 1GB?

I recall running LAMP stacks on something like 128MB about 20 years ago and not really having problems with memory. Most current website backends are not really much more complicated than they were back then if you don't haul in bloat.

It is. With 10k MRR it represents 0.15% of the revenue. Having the whole backend costing that much for a company selling web apps is like it’s costing zero.
You probably don't make 10k MMR on day one. If you make many small apps, it can make sense to learn how to run things lean to have 4x longer runway per app.
There’s a happy medium and $5 for 1GB RAM just isn’t it.
Not a very strong argument now is it?

if the project already has positive revenue then arguably the ability to capture new users is worth a lot, which requires acceptable performance even when a big traffic surge is happening (like a HN hug of attention)

if the scalability is in the number of "zero cost" projects to start, then 5 vs 15 is a 3x factor.

Be sure to inform the author of the article who is currently making money on his 1GB VPS that he hasn’t found a happy medium
Saving 15 USD on 10k+ USD MMR is ridiculous.
Given how much revenue depends on the experience of a web app and loading times, I’d be happy to pay 100$ a month on that revenue if I don’t have to sacrifice a second of additional loading time no matter how clever I was optimizing it.
Saving 15 USD on 0 USD MMR while still building the business is priceless. Virtually infinite runway.

NVME read latency is around 100usec, a SQLite3 database in the low terabytes needs somewhere between 3-5 random IOs per point lookup, so you're talking worst case for an already meaningful amount of data about 0.5ms per cold lookup. Say your app is complex and makes 10 of these per request, 5 ms. That leaves you serving 200 requests/sec before ever needing any kind of cache.

That's 17 million hits per day in about 3.9 MiB/sec sustained disk IO, before factoring in the parallelism that almost any bargain bucket NVME drive already offers (allowing you to at least 4x these numbers). But already you're talking about quadrupling the infrastructure spend before serving a single request, which is the entire point of the article.

You won't get such numbers on a $5 VPS, the SSDs that are used there are network attached and shared between users.

Not quite $5, but a $6.71 Hetzner VPS

# ioping -R /dev/sda

--- /dev/sda (block device 38.1 GiB) ioping statistics ---
22.7 k requests completed in 2.96 s, 88.8 MiB read, 7.68 k iops, 30.0 MiB/s
generated 22.7 k requests in 3.00 s, 88.8 MiB, 7.58 k iops, 29.6 MiB/s
min/avg/max/mdev = 72.2 us / 130.2 us / 2.53 ms / 75.6 us

I think we have to re-think and re-evaluate RAM usage on modern systems that use swapping with CPU-assisted page compression and fast, modern NVMe drives.

The Macbook Neo with 8GB RAM is a showcase of how people underistimated its capabilities due to low amount of RAM before launch, yet after release all the reviewers point to a larger set of capabilities without any issues that people didn't predict pre-launch.

Also, macOS is generally exceptional at caching and making efficient use of the fast solid state chips.
$5 VPS disks are nowhere near macbooks, they are shared between users and often connected via network. They don't seat close to CPU.

Or better yet, go with a euro provider like Hetzner and get 8GB of RAM for $10 or so. :)

Even their $5 plan gives 4GB.

They also have servers in the US (east and west coast).

> There are zero reasons to limit yourself to 1GB of RAM

There is a good reason: teaching yourself not to over-engineer, over-provision, or overthink, and instead to focus on generating business value to customers and getting more paying customers. I think it’s what many engineers are keen to overlook behind fun technical details.

> There is a good reason: teaching yourself not to over-engineer, over-provision, or overthink, (...)

This is specious reasoning. You don't prevent anything by adding artificial constraints. To put things in perspective, Hetzner's cheapest vCPU plan comes with 4GB of RAM.

If this sounds like basic advice, consider there are a lot of people out there that believe they have to start with serverless, kubernetes, fleets of servers, planet-scale databases, multi-zone high-availability setups, and many other "best practices".

Saying "you can just run things on a cheap VPS" sounds amateurish: people are immediately out with "Yeah but scaling", "Yeah but high availability", "Yeah but backups", "Yeah but now you have to maintain it" arguments, that are basically regurgitated sales pitches for various cloud platforms. It's learned helplessness.

Apparently the phrase cargo cult software engineering is not common anymore. Explains these things perfectly.

I end up explaining this term to every junior developer that doesn't know it sooner or later, the same way I explain bike shedding to all PMs that don't know it... often sooner, rather than later.

It seems to really help if you can put a term to it.

I don't know what to say. People keep saying these engineers exist and here I am not having seen a single, and I follow many indie hackers communities.
A devops coworker found my blog and asked me how I host it, is it Kubernetes. I told him it's a dedicated server and he seemed amazed. And this was just a blog. It's real
Does your coworker run a blog on k8s?
None of them self host anything at all. It's like that skill was totally skipped. But they advise and consult on infra
Well, by the time you are hiring a dedicated infra role, you should be past the single VPS stage.
Because I think precisely the indie hacker community is not as keen to default to the big-tech stacks, because those are neither indie, nor hack-y :)

> I use Linode or DigitalOcean. Pay no more than $5 to $10 a month. 1GB of RAM sounds terrifying to modern web developers, but it is plenty if you know what you are doing.

If you get one dedicated server for multiple separate projects, you can still keep the costs down but relax those constraints.

For example, look at the Hetzner server auction: https://www.hetzner.com/sb/

I pay about 40 EUR a month for this:

Disk: 736G / 7.3T (11%)
CPU: Intel Core i7-7700 @ 8x 4.2GHz [42.0°C]
RAM: 18004MiB / 64088MiB

I put Proxmox on it and can have as many VMs as the IO pressure of the OSes will permit: https://www.proxmox.com/en/ (I cared mostly about storage so got HDDs in RAID 0, others might just get a server with SSDs)

You could have 15 VMs each with 4 GB of RAM and it would still come out to around 2.66 EUR per month per VM. It's just way more cost efficient at any sort of scale (number of projects) when compared to regular VPSes, and as long as you don't put any trash on it, Proxmox itself is fairly stable, being a single point of failure aside.

Of course, with refurbished gear you'd want backups, but you really need those anyways.

Aside from that, Hetzner and Contabo (opinions vary about that one though) are going to be more affordable even when it comes to regular VPS hosting. I think Scaleway also had those small Stardust instances if you want something really cheap, but they go out of stock pretty quickly as well.

Refurbished server for sale in Hetzner Server Auction

Be quick and save money: Top and cheap refurbished dedicated servers at Hetzner Server Auction

What do you do about ipv4 ? Do you also use a routing VM to manage all that ?

It’s very interesting how people rent large VMs with a hypervisor. I’m wondering if licenses for VPS have any clauses preventing this for commercial scale.

I'm taking the opposite approach - managed services all the way, and my monthly infrastructure costs are higher than what's described here.

No regrets. Infrastructure isn't the problem I'm trying to solve. The problem is: who's actually going to pay for this?

Optimizing infrastructure before you have customers is like designing a kitchen before you've written the menu. I launched within 72 hours of starting development and went straight to customer validation. The market feedback started coming in immediately.

Infrastructure costs show up in your bill. The cost of slow customer validation doesn't show up anywhere - until it's too late. That's the number I watch.