Terraform won't make you cloud-portable — here's what actually will

July 16, 2026

There’s a line you hear every time someone talks about leaving a big cloud: “Just use Terraform, then you can move off AWS whenever you want.” I’m about to sit down and learn it properly — and because I advocate for getting off the big three (AWS, Azure, Google) onto flat-rate boxes like Hetzner and OVH, or even onto hardware in a client’s own offices, I want to get the pitch right before I put my name on it. So this is me working through the honest version, out loud, for anyone with a background like mine who’s wondering if it’s worth the time.

Short answer: yes, learn it — it’s close to essential for this kind of work. But the reason most people give for learning it is half-wrong, and if you repeat the half-wrong version to a client you’ll eventually get caught out. Let me take it apart.

First, what Terraform actually is (if you’ve never touched it)

If your infra life so far has been the AWS console, some systemctl on a box you SSH into, and a couple of cron jobs — that was me for a lot of years — here’s the one-sentence version. Terraform is a file that describes the infrastructure you want, and a command that makes reality match the file.

Instead of clicking through the EC2 console to create a server, a security group, and a Route53 record, you write something like:

resource "aws_instance" "web" {
  ami           = "ami-0abcd1234"
  instance_type = "t3.small"
}

…and run terraform plan (it shows you what it would change) then terraform apply (it does it). The language is HCL — declarative, boring, easy; you describe the end state, not the steps. It keeps a state file that records what it created, so next time it knows the difference between “create,” “change,” and “leave alone.” That state file is the whole ballgame, and I’ll come back to it.

For someone with 20 years of writing actual programs, HCL is not the hard part. You’ll be productive in an afternoon. The concepts that do take a beat are state management and the discipline that comes with it — more on that at the end.

The myth: “Terraform makes you provider-agnostic”

Here’s the thing to get straight, because it’s the load-bearing misconception. Terraform does not give you copy-paste portability between clouds. A config written for AWS is not a Hetzner config with a variable flipped.

Why not? Because Terraform talks to each provider through a provider plugin, and the resources are provider-specific all the way down:

Different resource names, different arguments, different networking models, different everything. Security groups, load balancers, object storage, managed databases, IAM — none of it maps one-to-one. Move from AWS to Hetzner and you are rewriting the provider-specific parts, not re-running the same file against a new endpoint. Anyone who shows a client a single Terraform repo and says “see, we’re provider-agnostic now” is selling a fiction, and it’s the kind that falls apart exactly when the migration gets real.

If I learned nothing else before advocating this tool, it’d be that. Say “portable” loosely and you’re wrong. So what’s the right claim?

What it actually buys you (bigger than the myth, just less magic)

The real win isn’t that the file moves. It’s that your infrastructure stops being invisible. Right now, on a lot of teams, the true description of “what’s running and why” lives in one overworked person’s head plus a thousand clicks nobody wrote down. Terraform turns that into:

Now connect that to cloud-exit. The reason leaving AWS is hard is almost never the compute — it’s that nobody can say precisely what’s running. When your infra is code, leaving becomes a project you can scope — read the file, list what has to be recreated on the new provider, rewrite those resources, apply. It’s still work. But it’s an engineering task with a known shape, not an archaeology dig through a console at 2am. That’s the real anti-lock-in win, and it’s worth saying in exactly those words: operational reproducibility, not copy-paste configs.

Say "portable" loosely and you're wrong.

The genuinely portable layer sits above Terraform

Here’s the part that made the whole picture click for me, and it’s why I’m not learning Terraform in isolation.

Terraform is day-zero provisioning — it makes the servers, networks, volumes, DNS records, and firewall rules exist. It says nothing about what’s on the box. And the stuff on the box — the packages, the users, the systemd units, the app itself — that layer genuinely is portable, because a Linux server is a Linux server whether Hetzner or OVH or a Dell in an office rented it to you.

So the stack that actually delivers on the “we can move” promise is two layers, and the second one is where my existing muscle memory pays off:

  1. OpenTofu / Terraform — provisions the infrastructure (the “what exists”). Provider-specific.
  2. Ansible + cloud-init — configures the machines: install packages, write config, set up systemd services, cron, users (the “how they’re set up”). Ansible playbooks move across providers almost unchanged, because they operate on a generic Linux box, not on a cloud API.
  3. (optional) Docker / k3s / Nomad for the workloads themselves — the most portable layer of all.

If you already live in systemctl and cron and SSH, Ansible is the natural next tool for you, not a new planet. It’s basically “the steps I’d type on the box, written down and made repeatable.” That’s why I’m pairing OpenTofu with Ansible rather than trying to make Terraform do everything. Terraform is bad at configuring the inside of a machine, and Ansible is the portable half of the story. Divide the labor: provision with one, configure with the other.

Provider reality for the places I actually want to send people

Since the whole point is getting off the big three, here’s the honest state of provider support for the targets I care about:

And the honest limit: for truly bare metal — a box with no virtualization layer, nothing with an API in front of it — Terraform is weak. That’s a different category of tool (MAAS, Tinkerbell) that does bare-metal provisioning. Know where that line is so you don’t promise Terraform somewhere it can’t help.

The multi-office / on-prem-backup case specifically

One thing I push with clients who have more than one physical office: those offices are latent infrastructure. Anything that isn’t customer-facing in real time — backups, batch jobs, internal tools, a warm standby, CI runners — can often live on a cheap box in an office instead of metered cloud. Can Terraform help there? Yes, with a caveat worth being straight about.

If each office runs a Proxmox (or vSphere) cluster, then absolutely — you point Terraform at each one and the whole fleet, across sites, becomes code. That’s a legitimately nice setup: one repo, VMs in three offices, all declared and reproducible.

But be honest about scale. For a handful of backup boxes, the value of Terraform over just… setting them up… is small, because there isn’t much provisioning to declare. There, the Ansible + cloud-init layer carries more weight — the value is in configuring those boxes identically and repeatably, not in provisioning a big fleet. Terraform earns its keep when there’s an API and enough resources to make “declare it as code” pay off. Below that threshold, reach for Ansible first. Matching the tool to the actual size of the job is the difference between advice and cargo-culting.

Divide the labor: provision with one, configure with the other.

Why I’m learning OpenTofu, not Terraform

This one matters more for me than for most, because I publicly argue against vendor lock-in — so I’d better not build my own practice on a tool that got relicensed out from under its community.

Quick history: for a decade Terraform was open source (MPL 2.0). In August 2023, HashiCorp relicensed it to the Business Source License (BUSL 1.1) — source-available, not open source, with a non-compete clause. The community forked the last open version into OpenTofu, now governed by the Linux Foundation. Then HashiCorp itself was acquired by IBM (closed in 2025). So the tool everyone means when they say “Terraform” is now a source-available IBM product.

OpenTofu is a drop-in replacement: same HCL, same workflow, same providers, state-compatible — you just type tofu instead of terraform. Everything I learn transfers 1:1. And it’s on message: recommending a BUSL-licensed IBM tool as the foundation of a “escape single-vendor dependence” strategy is a contradiction people will rightly call out. Picking OpenTofu is the same decision as leaving the hyperscalers, applied one layer up — an open, foundation-governed tool that can’t be relicensed on a whim.

Practically: I learn the exact same skills, I lose nothing, and I don’t have to explain an awkward inconsistency. Easy call. (I wrote up the full license story, the feature differences, and how to migrate an existing setup in an afternoon over here: Terraform vs OpenTofu.)

Where Pulumi fits — and why I’m not learning it right now

There’s a real alternative I want to name honestly, because for someone with my background it’s tempting: Pulumi. Instead of HCL, you write your infrastructure in an actual programming language — TypeScript, Python, Go. For a Node/React developer that can feel more natural than a new declarative DSL: real loops, real types, real functions, the tooling you already use.

So why am I parking it?

None of that means Pulumi is wrong — if your team is all TypeScript and allergic to a DSL, it’s a legitimately good fit, and knowing it exists is worth something. It’s in my back pocket as the “I already know TypeScript” accelerator. But I’m not spending the learning budget on it now. OpenTofu + Ansible first.

What the learning curve is actually like (for someone like us)

If you’ve got a couple of decades of tools behind you, don’t over-estimate this. The language is trivial — HCL is simpler than any programming language you already know. The parts that genuinely require attention:

Realistically: productive in a day, comfortable in a couple of weeks of real use, and the state/drift lessons land the first time they bite you. Cheap, for a skill this leveraged.

The bottom line

Is Terraform (as OpenTofu) worth learning for a 20-year developer who wants to help people get off the big clouds? Yes — it’s one of the highest-leverage skills for exactly this work, because “I’ll codify your infrastructure so leaving is a scoped project, not a hostage situation” is a real, sellable, honest pitch.

Just hold the claim precisely. It does not make configs portable between clouds. It makes your infrastructure legible and reproducible, which is what actually makes leaving possible. Pair it with Ansible for the portable configuration layer. Choose OpenTofu so the tool matches the philosophy. Keep Pulumi in your pocket, not on your plate. Get that framing right and you’re already ahead of most of the people confidently saying “just use Terraform.”


I’m learning this in the open because it’s the exact toolset behind the migrations I do: taking a team off metered hyperscaler billing and onto flat-rate boxes — or their own offices — with the whole setup written down so they’re never locked in again, to me or to a cloud. Every message comes straight to me and I reply to each one myself, usually within a day. If you want to know what your own exit would actually look like, send me a recent cloud bill and I’ll show you where the money goes and what a bounded, portable version costs instead — free, within a business day. Or if you’re weighing the bigger move, that’s what the Cloud-Exit Assessment is for.

Don't miss new posts

I publish honest, sourced breakdowns of cloud-exit economics — egress, storage, monitoring, reliability — and the occasional announcement. Leave your email and I'll let you know when something new goes up.

Double opt-in — you'll get one email to confirm. No spam, unsubscribe anytime. Read by me, never shared.