The article on Infrastructure as Code names drift as the model’s Achilles’ heel: the gap between what the code describes and what actually exists, which only gets fixed at the next terraform plan run by someone who thought to run it. Crossplane answers that exact problem with an architectural change, not a patch: it manages cloud infrastructure using the same continuous reconciliation mechanism Kubernetes already uses for its own pods.

Terraform: an apply-on-demand model

Terraform computes a plan at a specific moment, from stored state and configuration, then applies it once. Between two runs, nothing actively watches the infrastructure: a manual change made in the cloud console between two apply runs stays invisible until the next terraform plan, which reveals it as a diff, having never prevented it from happening in the first place.

# Terraform describes the target state, but only
# checks it when someone runs plan/apply
resource "aws_s3_bucket" "data" {
  bucket = "my-app-data"
}

Crossplane: every cloud resource is a reconciled Kubernetes object

Crossplane extends the Kubernetes API with CRDs representing cloud resources (an S3 bucket, an RDS database, a GKE cluster), managed by a controller running the same reconciliation loop that keeps a Deployment at its desired replica count. The resource is never “applied once”: it’s watched continuously, and any detected drift gets corrected automatically, with no human needing to rerun a tool.

apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
  name: my-app-data
spec:
  forProvider:
    region: eu-west-1
  # The Crossplane controller reconciles this object continuously,
  # exactly like any Kubernetes Deployment

A manual change made directly in the cloud console on a Crossplane-managed resource gets detected and reverted at the next reconciliation loop, usually within minutes, with no human action, exactly how Kubernetes replaces a manually deleted pod.

What this paradigm shift actually costs

Continuous reconciliation eliminates the silent drift window, but it requires operating one more Kubernetes controller (the Crossplane controller itself, plus one “provider” per cloud vendor) inside the cluster, an operational responsibility Terraform, a plain binary run from CI, doesn’t impose. Crossplane also assumes a team already comfortable with Kubernetes concepts (CRDs, controllers, kubectl) to manage infrastructure that itself doesn’t necessarily run inside the cluster.

The ecosystem, still uneven by provider

Terraform benefits from near-exhaustive coverage of every cloud provider, matured over nearly a decade. Crossplane providers, while covering the main use cases of major vendors (AWS, GCP, Azure), stay younger and less complete on niche resources: checking the maturity of the relevant provider before committing remains a required step, not a footnote.

Takeaway

Terraform applies a plan at a given moment, leaving a silent drift window between two runs; Crossplane eliminates that window by treating every cloud resource as a continuously reconciled Kubernetes object, exactly like a Deployment. That paradigm shift has a real cost: one more controller to operate, a Kubernetes skill requirement to manage infrastructure that doesn’t necessarily run there, and a provider ecosystem still less mature than Terraform’s on niche resources. The choice comes up naturally the moment a CI/CD industrialization has to decide how to handle infrastructure drift over the long run, not just at initial provisioning.