Infrastructure Debt
The most important command in my infrastructure toolkit isn't deploy. It's pulumi destroy.
That sounds wrong. We think about infrastructure in terms of building things. Setting up servers, provisioning databases, configuring storage buckets. The whole industry is oriented around getting things running. But if you're a solo developer, the activity you perform most often with infrastructure isn't setting it up. It's tearing it down.
I've been running multiple projects as a solo developer for a while now, and I've noticed something that nobody really talks about: I kill far more projects than I ship. This isn't a sign of failure. It's how exploration works. You try an idea, build a prototype, realize the market doesn't care or the technical approach doesn't hold, and you move on. The problem is that each abandoned project leaves behind a little graveyard of cloud resources. A database here, an IAM role there, a storage bucket with 200MB of test images, some DNS records pointing nowhere. None of it costs much individually. But collectively, across a dozen dead projects, it adds up. And the cognitive overhead of remembering what's still out there is worse than the money.
I call this infrastructure debt, and it's the solo developer's version of technical debt. Except it's sneakier, because it accumulates silently. You don't notice it until you check your cloud bill and find three databases you forgot to delete.
This insight β that teardown matters more than setup β is what drove every choice in my current stack. Let me walk through each piece.
I use GCP Cloud Run for compute. The reason is simple: it scales to zero. When nobody is hitting my API, I'm not paying for it. Not "paying a little." Paying nothing. This matters enormously when you're running five or six projects and only one or two have real traffic on any given day. A $5/month VPS doesn't sound expensive until you have eight of them for projects you haven't touched in months.
Cloud Run is also container-based, which means I'm not locked into any particular runtime or framework. I deploy Rust binaries for one project, a Node.js app for another. The deployment story is identical: build a container, push it, done. If I want to rewrite something in Go next year, nothing about the infrastructure changes. This portability isn't just convenient β it's another form of easy teardown. I can rip out the application layer without touching the infrastructure layer.
For databases, I use Neon. It's serverless PostgreSQL, and the key word there is PostgreSQL. Not PostgreSQL-with-extra-stuff-bolted-on. Just PostgreSQL. I write queries with SQLx in Rust, and I want compile-time verification against a real PostgreSQL database, not an abstraction that's mostly compatible.
But the feature that actually sold me on Neon is branching. I can fork my production database into a branch, test a migration against it, and throw the branch away. This is the kind of thing large teams solve with dedicated staging environments. Solo developers don't have that luxury. Database branching gives me the safety net without the operational overhead.
And like Cloud Run, Neon scales to zero. My development branches cost essentially nothing. When I abandon a project, there's no compute ticking away in the background. The pattern should be obvious by now: everything in this stack goes dormant when you stop using it.
For frontend hosting and storage, I use Cloudflare β Workers for serving applications, R2 for object storage. The obvious comparison is Vercel, and yes, Vercel has a more polished developer experience for Next.js. But Cloudflare's pricing model is in a different league. R2 charges zero egress fees. Zero. If you've ever run a photo-heavy application on S3 and watched the egress line climb, you understand why this matters. One viral moment and your storage bill goes from $2 to $200. With R2, it stays at $2.
Cloudflare Workers also run on over 300 edge locations worldwide, which means everything is fast everywhere without me thinking about regions. For a solo developer, the less I have to think about, the better. I want to point my domain at Cloudflare and forget about it.
Now here's where it all comes together: Pulumi.
Pulumi is Infrastructure as Code, like Terraform. You define your cloud resources in code, and the tool figures out how to create, update, or destroy them. The difference is that Pulumi lets me write that code in TypeScript β the language I already use every day. No HCL. No YAML. No new syntax to learn. Just TypeScript with type safety and IDE autocomplete.
But the reason Pulumi is the most important piece of this stack isn't the language. It's the destroy command. When I run pulumi destroy, it tears down everything β the Cloud Run service, the Neon database, the R2 bucket, the IAM bindings, the secrets β in the correct dependency order. Cleanly. Completely. Nothing left behind.
This is the superpower that makes the whole stack work for a solo developer. I can spin up a new project in an afternoon β copy the Pulumi template, adjust the names, run pulumi up β and I can tear it down just as fast when I decide it's not worth pursuing. The friction of creating infrastructure is low, but more importantly, the friction of destroying it is zero.
There's a subtle but important feature that makes this fearless destruction possible: the protect flag. For production resources I actually care about β like the database behind my one profitable project β I mark them as protected. Protected resources survive pulumi destroy. So I can be aggressive about cleanup without worrying about accidentally nuking something that matters. The protect flag turns pulumi destroy from a dangerous command into a routine one.
const db = new neon.Project("production-db", { ... }, { protect: true });
That one line is the difference between "I'd better be careful" and "let me just clean this up."
If I step back and look at the common thread, every choice in this stack optimizes for the same thing: low cost at rest and easy teardown. Cloud Run scales to zero. Neon scales to zero. Cloudflare charges nothing for egress. Pulumi destroys everything cleanly. The stack is cheap when I'm not using it and disappears when I'm done with it.
This is the opposite of how most infrastructure advice works. Most guides tell you how to build things that scale up. They assume your project will succeed and grow. But if you're a solo developer, the overwhelmingly likely outcome for any given project is that you'll abandon it. Optimizing for that case β making it cheap to keep and easy to kill β isn't pessimism. It's realism. And it's what gives you the freedom to start the next project without dragging the last one behind you.
The infrastructure that can't be easily destroyed is infrastructure you'll regret. pulumi destroy isn't the sad ending of a project. It's the clean slate that makes the next one possible.