Infrastructure as code is the practice of defining networks, clusters, and managed services in versioned, reproducible files rather than configuring them manually from a console. Terraform, Pulumi, and Crossplane implement it through three different models: trigger-based execution with state files, general-purpose code, and continuous reconciliation control planes.
Industry benchmarks reveal a stark divide: about 45% of organizations have adopted infrastructure as code practices and 74% of IT leaders consider it a critical enabler of cloud transformation1, but only 14% consistently demonstrate operational excellence in its execution.
Why the real IaC differentiator is the reconciliation model, not the language
The difference that matters across the three tools is when and how the actual state is compared to the desired state. Terraform and Pulumi perform this comparison only when someone runs a command or triggers a pipeline. Crossplane executes it continuously via the Kubernetes control loop. Everything else is ergonomics.

The debate over HCL versus TypeScript versus YAML affects the team learning curve, not the operational risk profile. In everyday practice, virtually all infrastructure definitions are purely declarative: a bucket, a subnet, a node pool. The power of a general-purpose language is needed in only a minority of cases, and they are almost always the same: dynamic resource generation from an external inventory, or complex conditional logic across environments. That complexity, however, does not stay isolated: it comes at a cost in code reviews, debugging, and onboarding across the rest of the codebase.
The three dimensions where the difference becomes measurable:
Configuration drift detection: in the trigger-based model, drift between two runs is an incident waiting to be discovered, often during an outage; in a control loop, it is caught and corrected in the next reconciliation cycle without human intervention. The actual latency is not a magical property of the paradigm: it depends on the reconciliation interval you configure and the provider API rate limits, so you can expect anywhere from tens of seconds to several minutes.
Change predictability: upfront planning in Terraform and Pulumi provides a readable, approvable diff before application; continuous reconciliation operates asynchronously, making it harder to get that same upstream validation.
Dependency on external pipelines: the first model lives inside CI/CD and inherits its waiting times; the second shifts intelligence inside the cluster, with your pipeline simply versioning intent.
Then there is the question of where state lives, which for a CTO is a matter of business continuity before architecture. A remote state file on S3 or GCS with locking introduces contention: in our experience on multi-cloud projects, monolithic state files shared across too many teams are a recurring cause of release bottlenecks, with pipelines queued up waiting for a lock released half an hour earlier. Crossplane eliminates the separate file and stores everything in etcd as Kubernetes resources, shifting the operational focus to backups, disaster recovery, and the cluster audit surface.
The core principles of declarative coding, from idempotency to environment reproducibility in CI/CD pipelines, remain valid across all three models: what changes is who steers the reconciliation. This is precisely the criterion by which they should be compared, because who owns the loop determines the three variables that truly matter in production: where the desired state lives, how much control remains with application teams, and how much operational overhead falls on you. The comparison below uses these three dimensions as an evaluation framework.
Comparing three models: what changes for the organization, not just the code
Terraform and OpenTofu represent the controlled-execution model with an external state file, Pulumi the programmatic model based on general-purpose languages, and Crossplane the continuous control plane model inside Kubernetes. The selection criterion is not syntax: it is how much centralized control you need and how much autonomy you want to grant application teams.
| Dimension | Terraform / OpenTofu | Pulumi | Crossplane |
|---|---|---|---|
| Language and format | HCL, declarative DSL | TypeScript, Python, Go, C# | YAML and Kubernetes API |
| State management | Remote state file with locking | Remote state file or managed backend | Resources in etcd, no separate file |
| Execution model | Trigger-based (CLI or pipeline) | Trigger-based (CLI, pipeline, automation) | Continuous control loop |
| Drift management | Detected only on execution | Detected only on execution | Automatically corrected |
| GitOps integration | Requires operators or wrappers | Kubernetes operator available | Native with Argo CD and Flux |
| Ideal team profile | Systems/infrastructure background | Mature software engineering | Cloud native platform engineering |
| Day-2 operational cost | Backend and module management | Code governance | Control cluster maintenance |
A common misconception must be clarified before moving forward: Ansible, Puppet, and Chef operate at a different layer. They are configuration management tools that act inside machines, not direct alternatives to cloud provisioning. Confusing them with the three models analyzed here leads to flawed architectural decisions.
Licensing context also needs to be considered. Terraform moving to the Business Source License sparked OpenTofu, a fork governed by the Linux Foundation, while the Crossplane core (a CNCF graduated project) and the Pulumi CLI remain under Apache 2.0. For those evaluating vendor lock-in and sovereignty over technology choices, this is not a legal detail: it is an evaluation criterion.
Terraform and OpenTofu: the established governance standard
The most concrete advantage remains the breadth of provider coverage. The three hyperscalers have official providers maintained in the registry, meaning that for most services encountered in projects, from GKE clusters on Google Cloud to AWS load balancers, a documented resource already exists. You rarely need to write custom integrations or fall back on direct API calls. That said, maturity varies across providers, and newer or niche services may have incomplete resources that lag behind official APIs. For decision-makers, the translation is direct: less custom code to maintain means less dependence on one or two people who understand it, and when the team wants to adopt a new cloud service, the path starts with a documented resource rather than a two-week spike to figure out how to integrate it.
The organizational strength is the clear separation between application code and infrastructure, paired with predictable behavior: upfront planning produces an approvable artifact, ideal for formal approval workflows and compliance checks with Sentinel or Open Policy Agent.
The limitation is structural. Between runs, drift remains invisible, and modularization has an expressiveness ceiling that becomes apparent when trying to build high-level abstractions: beyond a certain complexity, modules turn into Russian nesting dolls of variables that are hard to maintain.
Pulumi: infrastructure treated as first-class software
Here, infrastructure enters the same toolchain as application code: strong typing, IDE-assisted refactoring, unit testing with standard frameworks, and reuse via existing internal package managers. This is not an aesthetic convenience; it is code governance achieved through tools the team already masters.
In multi-tenant environments, where dozens of near-identical environments must be replicated per customer or per stage, documented enterprise cases report a dramatic leap: complex cluster provisioning drops from 1-1.5 weeks to less than a day. The mechanism is straightforward: topologies are generated parametrically via application code instead of duplicating configuration files that eventually drift apart.
For decision-makers, that metric translates into two practical benefits: a new environment stops being a ticket queued up for the infrastructure team and becomes a pipeline step, while freeing up engineering capacity currently spent reconciling configuration variants.
The trade-off must be made clear to decision-makers: maximum flexibility demands software engineering discipline. Without code reviews, automated testing, and shared internal standards, you produce non-deterministic infrastructure that is difficult to audit and even harder to justify to an external auditor.
Crossplane: Kubernetes as a unified infrastructure control plane
Crossplane is a CNCF Kubernetes Operator that maps cloud resources to provider-supplied Custom Resource Definitions (CRDs): managed databases, queues, buckets, and clusters become native Kubernetes API objects2. From there, they inherit the entire ecosystem for free, from Argo CD and Flux for GitOps to Prometheus for metrics, all the way to Kyverno for policies.
The real value, however, lies in Composite Resource Definitions (XRDs), with the composition model updated in Crossplane v2 in August 20253: they allow teams to expose high-level APIs to application developers, and as of this version, a Composition can include any Kubernetes resource, not just Crossplane-defined resources. The underlying mechanism is the same as the controllers that reconcile desired state with actual state in Operator patterns.
The hidden cost is a control cluster that must be managed and secured: etcd backups, RBAC, secrets, provider tuning, and cloud API rate limiting. As a Kubernetes Certified Service Provider, this is the area we see underestimated most often in initial assessments.
How IaC becomes the foundation of an Internal Developer Platform
How long do your developers wait for a staging database? If the answer is measured in days, the problem is not automation: it is that automation serves only the infrastructure team. Infrastructure as code becomes the foundation of an Internal Developer Platform (IDP) when it transitions from cluster-admin-managed provisioning to a self-service abstraction layer: internal APIs where application teams create resources pre-configured for security policies, naming conventions, and budget constraints, without opening tickets or writing a single line of Terraform.

Shifting the role of the platform team is the true strategic pivot. From an approval gatekeeper to a provider of golden paths: reusable modules, policies, and APIs. IaC is not about giving sysadmins less work; it is about removing the infrastructure team from the critical path of every release.
The abstraction is the product, not the tool. A Terraform module exposes parameters; a Crossplane XRD or a reusable Pulumi component exposes a product promise: “give me a complete staging environment”, “give me a Postgres instance compliant with our policies”. It is this semantic difference, rather than the tool, that reduces cognitive load and integrates with catalogs like Backstage, following an approach that platform engineering has operationalized in enterprise teams.
The maturity levels we observe in the field follow this sequence:
- Automated provisioning: resources are created from versioned code rather than consoles. This is the starting point, not the finish line.
- Shared modules: the platform team publishes reusable components with secure defaults.
- Self-service APIs with policies: teams provision resources autonomously within automatically verified constraints.
- Platform with catalog and observability: developer portal, usage metrics, and tracked ownership.
Security shifts left with policy-as-code: Sentinel or OPA for Terraform, native testing in Pulumi, Kyverno or OPA Gatekeeper for Crossplane, combined with static configuration scanning, centralized secrets management, and granular RBAC. When constraints are validated on every commit, auditing becomes a byproduct of the process rather than a standalone project: this is the difference between security enablement and security enforcement.
Finally, there is a FinOps lever that exists only when infrastructure is codified: ephemeral environments spun up and torn down on demand, scheduled off-hours shutdowns, and provisioning tied strictly to actual usage. Reproducible development environments go from hours of manual setup per developer down to a few minutes.
Which model to choose and when to combine them
The choice depends on two variables: the organization’s cloud native maturity and the rate of change in the layer being managed. If Kubernetes is not yet the internal standard, Crossplane introduces a cluster to maintain before it is genuinely needed. If formal approvals are required, Terraform or OpenTofu remain the lowest-risk option.

Translated into concrete criteria:
Choose Terraform or OpenTofu if your infrastructure team has a systems administration background, changes require an explicit approval workflow, and blast radius predictability is the top priority.
Choose Pulumi if you already have a solid software engineering culture with code reviews and automated testing, and you need dynamic logic for multi-tenant topologies or parametric environment generation.
Choose Crossplane if your workloads are already standardized on Kubernetes, GitOps with Argo CD or Flux is running in production, and your stated goal is exposing self-service APIs to application teams.
A layered IaC architecture is the rule, not the exception. The pattern we see succeed: a controlled-execution tool for the foundational layer, meaning networking, IAM, GKE, EKS, or AKS clusters, and shared services; a continuous control plane or programmatic components for the application layer and tenant-level managed services. The rule is simple: the layer that changes rarely and carries a high blast radius demands predictability and approval. The layer that changes daily demands self-service and self-healing.
Before deciding, four risks must be weighed: tool sprawl with pipelines that are impossible to debug (IaC failures are rarely technological, almost always organizational), more complex upfront validation in asynchronous models, cloud API rate limiting with dozens of active controllers, and maintaining control plane expertise. On interoperability, however, the risk is lower than often feared: Pulumi and Crossplane providers rely heavily on the Terraform ecosystem, so migrations are rarely a rip-and-replace effort. The same principles of architectural governance to mitigate tool fragmentation across multiple providers apply here.
Regarding timelines, a realistic outlook: initial measurable results on a bounded scope in a few weeks, while adopting a governed internal platform takes quarters, not sprints.
Conclusion: the decision is not about the tool
A language can be learned in a few weeks. An operating model takes years to change. The decision a CTO must sign off on comes down to how much centralized control to maintain, how much autonomy to grant application teams, and how much operational cost they are willing to absorb to achieve automated drift correction without human intervention.
It is worth acknowledging what remains unsolved. Upfront validation in continuous reconciliation models is still weaker than an approvable plan, and programmatic code governance depends on internal discipline before tooling. Anyone presenting either of these as solved problems is oversimplifying.
A practical test to evaluate where you stand: if your state file is shared across more than three teams and every deployment waits on a lock, the tool is not the issue. The real issue is the absence of a platform layer separating the foundational layer from the consumption layer.
If you want to assess where your infrastructure automation truly stands, book a 30-minute call with our DevOps and platform engineering team: together, we will map the state of your Terraform modules, pipelines, and drift across environments, and deliver an actionable list of priority improvements for your platform layer. We are a Kubernetes Certified Service Provider, CNCF members, with AWS and Google Cloud certifications.
Notes and sources
TEKsystems, “Top benefits of Infrastructure as Code (IaC)”: “Reflecting its growing strategic importance, 45% of organisations today are implementing IaC, while 74% of IT leaders view it as a key enabler of their cloud transformation efforts”. The figure of 45% of organizations adopting Infrastructure as Code practices, compared to 74% of IT leaders viewing it as a key enabler of cloud migration, is sourced from here: https://www.teksystems.com/en-hk/insights/article/top-benefits-infrastructure-as-code-iac ↩︎
Crossplane is a CNCF Kubernetes Operator that enables the creation and management of cloud resources via declarative Kubernetes syntax, mapping CRDs provided by crossplane-providers to vendor-specific cloud services without requiring application teams to write code. (source: Kubernetes Operator: cosa sono (con esempi)) ↩︎
the composition model updated in Crossplane v2 in August 2025: “Broader composition capabilities - Compositions can now include any Kubernetes resource, not just Crossplane-defined resources, enabling full-stack abstractions”: crossplane.io (source: https://blog.crossplane.io/announcing-crossplane-2-0/) ↩︎



