Infrastructure as code is the practice of defining networks, clusters, and managed services in versioned, reproducible files instead of configuring them manually from a console. Terraform, Pulumi, and Crossplane implement it through three different models: triggered execution with a state file, general-purpose code, and a continuous reconciliation control plane.
Industry numbers show a gap between adoption and execution. Around 45% of organizations are implementing infrastructure as code, and 74% of IT leaders consider it a key enabler of cloud transformation.1 But only 14% demonstrate the practices of those who truly execute it well, and those who succeed have a platform engineering team five times more often than the others.2 The gap rarely stems from the tool chosen: it depends on the reconciliation model built around it.
Why the real differentiator in IaC is not the language, but the reconciliation model
The difference that matters among the three tools is when and how actual state is compared with desired state. Terraform and Pulumi run the comparison when someone triggers a command or a pipeline; commercial backends add scheduled checks, such as HCP Terraform health assessments every 24 hours or Pulumi Cloud drift detection, which remain interval-based runs. Crossplane performs the comparison continuously via the Kubernetes control loop. Language, syntax, and tooling come after this choice.

The debate over HCL, TypeScript, or YAML is about the team’s learning curve, not the operational risk profile. In day-to-day practice, almost all infrastructure definitions are purely declarative: a bucket, a subnet, a node pool.
The power of a general-purpose language is needed in a minority of cases, almost always the same ones: dynamic resource generation from an external inventory, or complex conditional logic across environments. That complexity does not stay contained, however: it incurs costs in reviews, debugging, and onboarding across the rest of the codebase.
The three dimensions where the difference becomes measurable:
Configuration drift detection: in the triggered model, drift between two runs is an incident waiting to be discovered, often during an emergency; in the control loop, it is caught and corrected during the next reconciliation cycle, without human intervention. Latency depends on the reconciliation interval you configure and provider API rate limits: from tens of seconds to several minutes.
Change predictability: pre-execution planning in Terraform and Pulumi provides a readable, approvable diff before application; continuous reconciliation operates asynchronously, making the same upfront validation harder to achieve.
Reliance on external pipelines: the first model lives inside CI/CD and inherits its downtime and queues; the second moves the intelligence inside the cluster, with the pipeline merely versioning intent.
Then there is the question of where state lives, which for a CTO is about business continuity before architecture. A remote state file on S3 or GCS with locking introduces contention. In our experience on multi-cloud projects, a monolithic state file shared across multiple product teams is a recurring cause of slow releases: pipelines queue up waiting for a lock acquired half an hour earlier by another execution, or left hanging after an interrupted job.
Crossplane eliminates the separate file and stores state in etcd as Kubernetes resources. The issue does not disappear, however: it shifts 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. And whoever owns the loop determines the three variables that matter in practice: where the desired state lives, how much control the application team retains, and how much operational overhead remains on your plate.
Comparing three models: what changes for the organization, not just for 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, but how much centralized control is needed 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#, Java, YAML | 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 | Triggered (CLI or pipeline) | Triggered (CLI, pipeline, automation) | Continuous control loop |
| Drift management | On execution, or scheduled in HCP Terraform | On execution, or scheduled in Pulumi Cloud | Automatically corrected |
| GitOps integration | Requires operators or wrappers | Kubernetes operator available | Native with Argo CD and Flux |
| Ideal team profile | Systems administration background | Mature software engineering | Cloud-native platform engineering |
| Day-2 operational cost | Backend and module management | Code governance | Control cluster maintenance |
A technical clarification: Ansible, Puppet, and Chef are not alternatives to these three tools. They are configuration management tools operating inside machines, not cloud provisioning tools. Confusing them leads to poor architectural decisions.
Licensing also plays a role. In August 2023, HashiCorp shifted Terraform to the Business Source License, leading to the creation of OpenTofu, a fork now governed by the Linux Foundation. Crossplane core (a graduated CNCF project) and the Pulumi CLI remain under Apache 2.0.
The Terraform case demonstrates that a license can change after years of adoption, once the tool is already deeply embedded in pipelines, modules, and team skillsets. That is why, in our open-source approach, governance carries as much weight as features when selecting an IaC tool for a client: we examine who holds the copyright, whether the project is housed in a neutral foundation, and whether the license is OSI-approved.
Terraform and OpenTofu: the consolidated 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 and writing custom integrations is rarely necessary. Maturity varies across providers, and for newer or niche services, resources may be incomplete or lag behind the APIs.
Less custom code to maintain means less dependency on one or two people capable of understanding it. When the team adopts a new cloud service, they start from a documented resource rather than two weeks of exploratory analysis to figure out how to integrate it.
The organizational strength is the clean separation between application code and infrastructure, combined with predictable behavior: upfront planning produces an approvable artifact suitable for formal authorization workflows and compliance checks using Sentinel or Open Policy Agent.
There are two structural limitations. The first is the flip side of predictability: drift remains invisible between runs, because comparison with actual state only happens when someone triggers a plan. The second is HCL’s expressiveness ceiling: when attempting 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 the application: strong typing, IDE-assisted refactoring, unit tests with standard frameworks, and reuse via existing internal package managers. It is code governance achieved through tools the team already masters.
The gains can be substantial in enterprise contexts. Snowflake, in a case study published by Pulumi, reported reducing cluster deployment times from a week or a week and a half to under a day across AWS, Azure, and Google Cloud.3
This mechanism shines especially in multi-tenant contexts where dozens of nearly identical environments must be replicated per customer or stage: topologies are generated parametrically via code instead of duplicating configuration files that eventually drift apart.
That number brings two benefits. Spinning up a new environment stops being a ticket queued for the infrastructure team and becomes a step inside the pipeline. And it frees up capacity currently spent reconciling configuration variants.
The trade-off: 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 explain to an external auditor.
Crossplane: Kubernetes as a single infrastructure control plane
Crossplane is a graduated CNCF project: a set of Kubernetes controllers mapping cloud resources to Custom Resource Definitions (CRDs) provided by plugins. Managed databases, queues, buckets, and clusters become native objects of the Kubernetes API4 and integrate without additional adapters into tools that already read that API: Argo CD and Flux for GitOps, Prometheus for metrics, and Kyverno for policies.
The real value lies in Composite Resource Definitions (XRDs), featuring the composition model updated with Crossplane v2 in August 20255: they allow exposing high-level APIs to application teams, and as of this version, a Composition can include any Kubernetes resource, not just those defined by Crossplane. The underlying mechanism is the same one controllers use to reconcile desired state and actual state in Operator patterns.
The hidden cost is a control cluster to operate and secure: etcd backups, RBAC, secrets, provider tuning, and cloud API rate limiting. As a Kubernetes Certified Service Provider, this is the factor we see underestimated most frequently during 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 only serves the infrastructure team. Infrastructure as code becomes the foundation of an Internal Developer Platform (IDP) when it transitions from provisioning managed by cluster administrators to a self-service abstraction layer. In practice, application teams use internal APIs to create resources that already comply with security, naming, and budget policies, without opening a ticket or writing a single line of Terraform.

The changing role of the platform team is the strategic point. Shifting from authorization gatekeepers to providers of golden paths: reusable modules, policies, and APIs. IaC is not about lightening the sysadmin workload; 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”.
This semantic difference, not the tool, reduces cognitive load and integrates with catalogs such as Backstage, following the model that platform engineering has made operational within enterprise teams.
The maturity levels we observe in the field follow this sequence:
- Automated provisioning: resources originate from versioned code, not 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 create resources autonomously within automatically verified boundaries.
- Platform with catalog and observability: developer portal, usage metrics, and tracked ownership.
Security shifts left with policy-as-code: Sentinel or OPA on HCP Terraform, Conftest or Checkov in pipelines for open source, CrossGuard for Pulumi, Kyverno or OPA Gatekeeper for Crossplane, combined with static configuration scanning, centralized secret management, and granular RBAC.
If rules run in the pipeline on every commit, developers immediately discover whether a bucket is public or missing a cost tag and correct it themselves, without opening a ticket for the security team. The alternative is downstream manual review, which blocks releases after code has already been written. Rules remain mandatory, but enforcement happens earlier and automatically, making audits a natural byproduct of the process rather than a standalone project.
Finally, there is a FinOps lever that only exists when infrastructure is codified: ephemeral environments created and destroyed on demand, scheduled off-hours shutdowns, and provisioning tied strictly to actual usage. A reproducible development environment is provisioned in minutes rather than hours of manual per-developer setup.
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 governed. If Kubernetes is not yet the internal standard, Crossplane introduces a cluster to maintain before it is needed. If formal approvals are required, Terraform or OpenTofu remain the lowest-risk option.

In practice:
Choose Terraform or OpenTofu if your infrastructure team has a systems administration background, changes require an explicit approval path, and predictability regarding blast radius is paramount.
Choose Pulumi if you already possess a solid software engineering culture with code reviews and automated testing, and you require 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 in production, and the explicit goal is exposing self-service APIs to application teams.
A layered IaC architecture is the rule, not the exception. The pattern we see succeed separates two layers. The foundational layer, covering networking, IAM, managed clusters such as GKE, EKS, or AKS, and shared services, changes rarely and carries a broad blast radius: it requires predictability and approval, pointing to a controlled execution tool like Terraform or OpenTofu. The application layer, containing per-tenant managed services, changes daily: it demands self-service and self-healing, pointing to a continuous control plane like Crossplane or programmatic components like Pulumi.
Before deciding, four risks must be evaluated: tool sprawl resulting in un-debuggable pipelines (IaC failure is rarely technological, almost always organizational), more complex upfront validation in asynchronous models, cloud API rate limiting with dozens of active controllers, and maintaining the specialized skills required for the control plane.
Interoperability risks are lower than usually feared: Pulumi and Crossplane providers largely build upon the Terraform ecosystem, meaning 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 expectation: initial measurable results within a scoped perimeter in a few weeks; adoption of a fully governed internal platform spans quarters, not sprints.
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 approve is about how much centralized control to retain, how much autonomy to grant application teams, and how much operational overhead the organization is willing to internalize to achieve automated drift correction without human intervention.
Two challenges remain open. Pre-execution validation in continuous reconciliation models is weaker than an approvable plan, and programmatic code governance relies on internal discipline before tooling.
A practical test to assess where you stand: if your state file is shared by more than three teams and every deployment waits on a lock, the problem is not the tool. It is the absence of a platform layer separating the foundational layer from the consumption layer.
If you want to understand where your infrastructure automation stands, book an initial discussion with our DevOps and platform engineering team. It helps assess your current state and determine whether an evaluation of your automation maturity, followed by the design of an appropriate platform layer, makes sense for your organization. We are a Kubernetes Certified Service Provider, CNCF members, with AWS and Google Cloud certifications.
Notes and sources
Note e fonti
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”. (source: https://www.teksystems.com/en-hk/insights/article/top-benefits-infrastructure-as-code-iac) ↩︎
Spacelift, “2025 Infrastructure Automation Report”, survey conducted by Panterra among 413 infrastructure decision-makers: 45% state they have achieved a high level of automation, only 14% demonstrate operational excellence practices. (source: https://spacelift.io/blog/the-illusion-of-infrastructure-automation-maturity) ↩︎
Pulumi, Snowflake case study: Raman Hariharan, Director of Cloud Platform Engineering, reports reducing cluster deployment from “a week or a week and a half” to “under a day”. (source: https://www.pulumi.com/case-studies/snowflake/) ↩︎
Crossplane is a CNCF project that enables creating and managing cloud resources using declarative Kubernetes syntax, mapping provider CRDs to vendor services without requiring application teams to write code. (source: Kubernetes Operator: cosa sono (con esempi)) ↩︎
Crossplane 2.0, announcement of August 12, 2025: “Broader composition capabilities: Compositions can now include any Kubernetes resource, not just Crossplane-defined resources, enabling full-stack abstractions”. (source: https://blog.crossplane.io/announcing-crossplane-2-0/) ↩︎





