Crossplane extends the Kubernetes API to manage infrastructure outside the cluster — an RDS instance, an S3 bucket, a VPC — using the same declarative, reconciliation-loop model Kubernetes already uses for pods and deployments. Instead of a separate Terraform pipeline that runs on a schedule or on merge, infrastructure becomes a Kubernetes resource that a controller continuously reconciles toward the desired state, the same way a Deployment controller keeps pod replicas at the requested count.
Providers and managed resources
A Crossplane provider (provider-aws, provider-gcp, provider-azure, and many community providers for other services) installs CRDs and controllers for that cloud's resources. Once installed, you can create a Bucket or a RDSInstance as a Kubernetes object, and the provider's controller talks to the cloud API to make reality match the spec — including reconciling drift if someone changes the resource outside Crossplane, which is a meaningful difference from Terraform's plan-and-apply model that only checks drift when you explicitly run it.
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: app-uploads
spec:
forProvider:
region: eu-west-1
tags:
environment: production
providerConfigRef:
name: aws-provider-config
Compositions: the platform-team abstraction layer
Raw managed resources are still cloud-specific and detailed — not something you want application teams writing directly. A Composition lets a platform team define a higher-level abstraction (a PostgresDatabase claim, say) that expands into the actual set of managed resources — an RDS instance, a security group, a subnet group, a secret — behind a much simpler interface. Application teams request the abstraction; the platform team owns and evolves what it expands into, which is the core value proposition: self-service infrastructure requests that stay within guardrails the platform team controls.
Once application teams are creating claims against a Composition, changing the Composition's shape is a breaking-change decision, same as changing any API. Version Compositions deliberately and think about migration for existing claims before changing the fields a claim can set — this is easy to treat casually early on and expensive to fix once dozens of claims depend on the old shape.
Crossplane vs Terraform: not a strict replacement
Terraform's model is plan-review-apply, usually gated through CI/CD with a human approval step — good for changes where you want an explicit diff reviewed before anything happens. Crossplane's model is continuous reconciliation — good for infrastructure that should self-heal and for exposing infrastructure provisioning as a Kubernetes-native, GitOps-friendly API to teams already living in kubectl and Git. They're not mutually exclusive in a given organization; many teams use Terraform for foundational, rarely-changed infrastructure (the VPC, the cluster itself) and Crossplane for the higher-churn, per-application resources that benefit from self-service and continuous drift correction.
GitOps fits naturally
Because Crossplane resources are ordinary Kubernetes objects, they work with Argo CD or Flux the same way any other manifest does — commit a claim to Git, the GitOps controller applies it, Crossplane reconciles the underlying cloud resources. This is a genuine operational win over a separate Terraform pipeline: one review-and-audit trail (Git history) for both application deployments and the infrastructure they depend on, rather than two disconnected systems with their own approval flows.
Don't try to model your entire cloud footprint in Crossplane on day one. Pick the resource type application teams request most often — a database, a queue, an object storage bucket — build one solid Composition for it, and prove the self-service workflow before expanding. A half-finished Crossplane rollout covering three resource types badly is worse than one resource type covered well.
| Concern | Terraform | Crossplane |
|---|---|---|
| Change review | Explicit plan/apply, easy to gate | Continuous reconciliation, gated via Git review of the claim |
| Drift handling | Detected on next plan run | Continuously reconciled by the controller |
| Self-service for app teams | Needs a separate wrapper/portal | Native via Compositions and claims |
| Ecosystem maturity | Very mature, broad provider coverage | Growing, strong on major clouds, thinner elsewhere |
Wrapping up
Crossplane is worth adopting when the goal is genuine self-service infrastructure inside a Kubernetes-native, GitOps workflow — not as a wholesale Terraform replacement. Start narrow with one Composition for your highest-demand resource type, treat that Composition's shape as a versioned API, and expand once the workflow has proven itself with real application teams using it.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.