Terraform 1.17.0-alpha: what changed and should you run it? (published July 29, 2026): this is a prerelease, not a stable Terraform 1.17.0 release. The authoritative tag is v1.17.0-alpha20260729; the latest stable line remains 1.15.x as of this refresh. The alpha adds provider-version details to terraform init log messages and fixes pow and log from panicking when their result is NaN. It also carries alpha-only experiments: deferred actions behind -allow-deferral, test cleanup, persistent test backends and skip_cleanup, and policy evaluation through terraform query -policies. HashiCorp explicitly says these experiments are not available in stable releases.

For an AI platform's production IaC, keep the stable pin. Use this alpha only in an isolated CI matrix if you need to test deferred actions or the new diagnostics; do not promote it as the baseline for a GPU cluster. The release notes contain no upgrade notes or breaking-change section, but prerelease status is itself the operational warning. The Kubernetes GPU Operators guide is the adjacent deployment reference to exercise when an IaC change reaches the cluster, and the AWS FinOps agent guide covers the cost attribution that should inform a multi-cloud module decision.

What's New in Pulumi 3.255.0 (released 2026-07-28): a CLI-and-engineering-focused feature drop with no breaking changes. Three changes matter for AI infrastructure teams who keep their IaC close to the GPU cluster. --extension flag on package commands — extension-parameterized packages can be reinstalled from Pulumi.yaml on pulumi install, so an ML platform team that ships a custom provider for a niche accelerator (e.g. an in-house TPU-like scheduler) no longer needs a separate reinstall step after a stack refresh. Project files surfaced as environment variables on ESC open (#23993) — when you open an ESC environment, Pulumi writes the project files to disk and exposes their paths as environment variables across all output formats. That makes downstream tools (training orchestrators, vector DB clients, FinOps agents) reach their config without a parallel secret loader. Invoke provider resolution now matches resource registration (#24016) — the engine resolves an invoke's provider from the providers option of the parent named on the request, the same resolution path that resource registrations use. The provider-mismatch footgun that affected multi-cloud stacks (an invoke accidentally hitting the wrong region) is now harder to trip. Two smaller CLI additions round out the drop: --resources on do input expressions (#24037) to reference existing state resources, and a nodejs programgen fix (#24017) that parents an invoke inside a component to that component so it resolves the component's providers. For teams already running multi-cloud GPU training pipelines with the Kubernetes GPU scheduling guide, the ESC env-var change is the most directly useful — the orchestrator no longer has to be told where its config lives. The 3.254.0 production pin holds; 3.255.0 is a drop-in upgrade.
What's New in Pulumi 3.254.0 (released 2026-07-23): a CLI-focused feature drop with three changes that matter for AI infrastructure teams. pulumi logs share (#22546) — share a running service's logs with Pulumi support or a teammate via a one-shot shareable token, useful when an ML platform engineer is on call and needs to pull a live log stream from a flaky training orchestrator without handing over cloud credentials. pulumi stack migrate (#22902) — migrate a stack from one backend to another (e.g. moving a self-hosted Pulumi Service backend to Pulumi Cloud, or moving between S3 buckets) with automatic re-encryption of config secrets and stack state under the target secrets provider; previously this was a manual export/import cycle that required you to decrypt and re-encrypt every secret. --override-env (#23562) on up, preview, destroy, and refresh — substitute a different environment configuration for a single run without editing the stack config, useful for running a dry-run of a GPU cluster change against a staging environment while the real stack stays on prod. The 3.254.0 line also adds the pulumi neo acp agent-client-protocol integration (#23886), the pulumi neo resume command (#23835) with chat history, and Ctrl+A / Ctrl+E line-navigation preservation in the Neo REPL (#23932) — Pulumi's AI assistant is graduating from a CLI toy into a real infrastructure workflow tool. None of these are breaking changes; the 3.253.0 production pin holds. For teams that already use the patterns in the Kubernetes GPU scheduling guide, the --override-env flag is the most directly useful — it lets you preview a cluster re-size against a staging config without touching the prod stack.

If you are standing up a GPU training cluster, deploying a model serving endpoint, or wiring up a vector database on Kubernetes, you need to provision infrastructure reproducibly. Spinning up a cluster manually through a cloud console works once. It does not work when you need to tear it down and rebuild it at 3 AM during an incident, or when your training pipeline needs to provision a fresh compute environment for every experiment run.

Infrastructure as Code (IaC) solves this. And for AI and ML teams, two tools sit at the top of the evaluation list: Terraform (HashiCorp) and Pulumi (Pulumi Corp). This is not a generic comparison — it is a practical guide for AI infrastructure decisions: GPU clusters, Kubernetes, multi-cloud routing, and the specific demands that ML workloads place on your provisioning layer.

The Fundamental Difference: Declarative vs Programmatic

Terraform and Pulumi approach infrastructure as code in fundamentally different ways, and understanding this difference is the key to making the right choice for your team.

Terraform uses HashiCorp Configuration Language (HCL), a declarative domain-specific language. You describe the desired state of your infrastructure in .tf files, and Terraform figures out how to reach that state. You write configuration; Terraform plans and applies. The state file (typically stored in Terraform Cloud or locally) tracks what exists, and Terraform reconciles your configuration against that state on every apply.

Pulumi uses general-purpose programming languages — Python, TypeScript, Go, C#, or Java. You write real code that creates and configures infrastructure. Pulumi still has a plan and apply workflow, but because you are writing code, you can use loops, conditionals, functions, and classes to model complex infrastructure patterns. A Python Pulumi program can call a function that generates a GPU cluster configuration, and that function can embed business logic that would be impossible to express in HCL.

For AI infrastructure specifically, this difference matters in several concrete ways.

Dynamic GPU Cluster Provisioning

AI workloads are not static. A training run needs dozens of A100 GPUs for four hours and then the cluster sits idle. An inference service has baseline capacity that spikes at 10 AM when batch processing kicks in. Traditional infrastructure can be provisioned once; AI infrastructure needs to breathe.

Terraform handles dynamic provisioning through data sources, dynamic blocks, and for_each expressions — and it works. You can provision a fleet of GPU instances with Terraform. But the HCL syntax for dynamic clusters is verbose, and the plan/apply cycle must run to completion before Terraform knows what changed. For rapidly scaling GPU clusters where the provisioning logic depends on runtime data (spot instance availability, current job queue depth), Pulumi's native Python loops and runtime API calls fit more naturally.

In Pulumi, you can write a function that queries the current spot instance availability across AWS and GCP, compares pricing, and provisions the optimal cluster — all in a single Python script with standard control flow. In Terraform, this requires external data sources, complex module composition, and often a separate orchestration layer.

Advertisement
Advertisement

Kubernetes and ML Tooling Integration

Most AI infrastructure runs on Kubernetes, and both Terraform and Pulumi have strong Kubernetes support. But the experience differs.

Terraform's kubectl provider and helm provider are mature and battle-tested. You can define a complete Kubernetes cluster, install the Karpenter autoscaler, deploy a KubeRay operator, and configure a model serving layer — all in Terraform HCL. The Terraform Registry has providers for every major cloud and many specialized tools (NVIDIA GPU operators, Prometheus, Grafana). For teams that want to define their entire infrastructure in one place, Terraform's provider ecosystem is unmatched.

Pulumi's Kubernetes provider is equally capable, but goes further — you can use the Pulumi Kubernetes SDK to create Kubernetes resources directly from Python or TypeScript, and you can embed raw YAML generation inside Python functions. This is particularly useful for ML tooling like KubeFlow pipelines, Ray clusters, and Seldon model servers where the resource definitions are complex and often generated programmatically. Pulumi's ConfigFile and Chart abstractions let you mix raw YAML with Pulumi-managed resources, giving you flexibility without abandoning the Pulumi programming model.

Both tools handle Custom Resource Definitions (CRDs) well, but Pulumi's ability to iterate over CRDs in Python makes it easier to manage large collections of similar resources — for example, dozens of inference endpoints across different model versions.

Multi-Cloud GPU Routing

AI infrastructure increasingly spans multiple cloud providers. Lambda Labs and RunPod offer GPU compute that AWS and GCP cannot match on price for certain workloads. CoreWeave has become the de facto choice for some vLLM deployments. Team members may develop on a local Ray cluster and deploy to a cloud provider for production.

Terraform addresses multi-cloud through its provider ecosystem. Each cloud provider has an official Terraform provider, and you can write Terraform configuration that targets AWS for some resources and GCP for others. The challenge is that each provider is a separate plugin, state management spans providers awkwardly, and expressing cross-cloud logic (like "route training jobs to the cheapest available GPU right now") requires external scripts or a higher-level orchestration tool.

Pulumi's multi-cloud SDK abstracts provider differences in code. The same Python function can target AWS EC2 or GCP Compute Engine, and the function can make runtime decisions based on pricing APIs, availability, or custom constraints. For teams building ML platforms that need to route workloads dynamically across GPU providers, Pulumi's programmatic model is a significant advantage.

State Management for AI Workloads

Both Terraform and Pulumi track infrastructure state, but the operational characteristics matter for AI teams.

Terraform stores state in a flat file (by default locally, or in Terraform Cloud for team environments). As infrastructure grows — hundreds of GPU instances, multiple Kubernetes clusters, complex networking — the state file grows and the plan step slows. Terraform's state locking prevents concurrent applies from corrupting state, which is critical when your training pipeline provisioner and your incident response script might both try to modify infrastructure simultaneously.

Pulumi stores state in the Pulumi Cloud Service (a SaaS offering with a generous free tier) or in a self-hosted backend. The Pulumi Service handles state locking, history, and team collaboration automatically. Pulumi also supports checkpointing — every successful apply creates a checkpoint you can roll back to. For AI infrastructure teams that move fast and sometimes need to undo a bad provisioning run, this is valuable.

One concrete advantage of Pulumi's state management: because Pulumi programs are real code, you can write unit tests for your infrastructure using standard Python testing tools (pytest). You can test that your GPU cluster configuration creates the right number of instances, that your security group rules are correct, and that your cost tagging strategy is applied consistently — before you run pulumi up.

Real-World Example: Provisioning a GPU Spot Cluster

Consider the practical task of provisioning a GPU training cluster using AWS EC2 Spot Instances. Both Terraform and Pulumi can do this, but the implementation differs.

In Terraform, you would use a combination of aws_ec2_spot_fleet or aws_launch_template with spot options, an autoscaling group, and conditional block device mappings. The configuration involves multiple resources with complex dependencies. Handling spot interruptions (when AWS reclaims your instances) requires external automation — a Lambda function triggered by CloudWatch events, for example.

In Pulumi (Python), the same provisioning logic is a Python function that creates the autoscaling group, configures the launch template, and attaches a CloudWatch event rule that triggers a handler when a spot interruption notice arrives. That handler — also in Python — can decide whether to wait for replacement capacity, scale down gracefully, or notify the training job scheduler. Because it is all Python, the spot interruption handler can call your job queue API, update a tracking database, and send a Slack notification — all in the same codebase.

The Terraform equivalent requires Terraform configuration plus external Lambda code in a different language. The Pulumi version keeps everything in one language, one codebase, one review process.

Comparison Table: Terraform vs Pulumi for AI Infrastructure

Dimension Terraform Pulumi
Language HCL (declarative DSL) Python, TypeScript, Go, C#, Java
Learning curve Steeper for engineers without HCL experience; HCL is unique to Terraform Easier for teams that already write Python or TypeScript
AI/ML workload flexibility Good for static configs; dynamic provisioning requires external scripts Native loops, conditionals, and runtime API calls handle dynamic workloads naturally
Kubernetes support Mature kubectl and Helm providers; extensive CRD support Strong K8s SDK; can embed YAML generation in Python; ConfigFile for mixing approaches
Multi-cloud GPU routing Provider ecosystem (AWS, GCP, Azure mature); cross-cloud logic needs orchestration layer Native multi-cloud SDK; runtime decisions across providers in one language
State management Local or Terraform Cloud; state locking; large state slows plan Pulumi Service (SaaS) or self-hosted; automatic state locking and checkpointing
Cost Open-source core; Terraform Cloud free tier (500 actions per month); Team at 20 dollars per user per month Free tier (unlimited resources); Team at 0 dollars per user per month; Enterprise at 15 dollars per user per month
Testing Terraform validate, plan; limited unit testing Native pytest, Go, TypeScript testing; test infrastructure before apply
Module ecosystem Terraform Registry — thousands of providers and modules Pulumi Package Registry — growing, but smaller than Terraform Registry
AI GPU provider support AWS, GCP, Azure providers mature; RunPod and Lambda Labs providers exist AWS, GCP, Azure providers; Lambda Labs and custom providers via Pulumi SDK
Vendor lock-in Low (open-source core, Terraform Cloud is optional) Low (open-source core, Pulumi Service is optional)
Team collaboration Terraform Cloud or Terraform Cloud for Teams; VCS integration Pulumi Service with team dashboard, audit logs, policy as code

When to Choose Terraform

Terraform is the right choice when your team already knows Terraform and has established modules and patterns. IaC is only valuable if your team actually uses it. If your infrastructure is relatively static — managing production Kubernetes clusters, VPC networks, and storage that do not change frequently — Terraform's declarative model is clean and auditable. You write the config, review the plan, apply, and move on.

You need the Terraform Registry ecosystem when you are working with specialized infrastructure: NVIDIA GPU operators, cloud-specific ML services, monitoring integrations. Terraform's provider ecosystem is deeper. If a managed service you need is not in Pulumi's registry, it is almost certainly in Terraform's.

Compliance requires immutable, auditable infrastructure when every infrastructure change must be reviewed and approved (SOC2, HIPAA, GDPR-adjacent). Terraform's plan/apply workflow provides a clean audit trail. And if you are running standard multi-cloud patterns — using both AWS and GCP with standard resource types — Terraform's provider model covers it without needing the programmatic flexibility of Pulumi.

When to Choose Pulumi

Pulumi is the right choice when your team writes Python or TypeScript for ML pipelines. If your ML engineers are already writing PyTorch training scripts, data processing pipelines, or model serving code in Python, Pulumi integrates naturally. Your infrastructure team can write IaC in the same language as your ML team and share libraries.

AI infrastructure that is dynamic and complex — GPU clusters that scale based on job queue depth, training workloads routed across spot instance availability, multi-cloud inference endpoints with dynamic routing — all benefit from Pulumi's programmatic model over Terraform's declarative approach.

Pulumi programs are Python (or TypeScript, Go, etc.), which means you can write unit tests using pytest, assert on resource properties, and validate complex configurations before running pulumi up. For AI infrastructure where a misconfigured security group can expose a model endpoint, testing is not a luxury — it is a necessity.

Pulumi can be called programmatically from Python, which means your training pipeline can provision its own compute environment, wait for resources to be ready, run the training job, and tear down the cluster — all without a separate IaC workflow. Terraform requires an external trigger (a CI/CD pipeline step, a Terraform Cloud run). And if you are building a self-service ML platform where ML engineers provision their own training environments through a portal, Pulumi's programmatic model lets you build typed, documented APIs for infrastructure provisioning that feel like normal Python libraries.

Recommended Tool Pulumi

Pulumi's open-source IaC lets your ML team use real programming languages for infrastructure. Free for individuals and small teams.

The Hybrid Approach: Use Both

The most common pattern for mature AI platforms is not "Terraform OR Pulumi" — it is "Terraform for base infrastructure, Pulumi for workload-specific provisioning." This is practical, not ideological.

Terraform for the base layer: VPC networking, IAM roles and policies, core Kubernetes control plane, centralized logging and monitoring infrastructure. These are static, well-defined, and benefit from Terraform's auditable plan/apply workflow and massive module ecosystem. You define this once, review it carefully, and apply it when you stand up a new environment.

Pulumi for dynamic workloads: Training clusters, model serving endpoints, feature stores, experiment tracking infrastructure, and any provisioning that needs to respond to runtime conditions (job queue depth, spot pricing, model version). These change frequently, often need custom logic, and are natural candidates for Pulumi's programmatic model. Your ML platform team can own the Pulumi programs for workload provisioning without needing to understand the entire infrastructure stack.

Pulumi can manage Terraform state through the @pulumi/terraform provider, and Terraform can import Pulumi stacks — so the boundary between the two is not a wall but a permeable membrane. Many teams start with Terraform, realize they need more flexibility for AI workloads, and add Pulumi incrementally without migrating existing infrastructure.

Decision Framework

Is your AI infrastructure mostly static? (Production Kubernetes, VPC, managed services that do not change frequently) — Choose Terraform. Lower learning curve within your existing team, massive module ecosystem, clean audit trail.

Does your team already write Python or TypeScript for ML work? — Lean toward Pulumi. Your team can own infrastructure without learning HCL, and your ML pipelines can call provisioning logic directly.

Do you need to route workloads dynamically across multiple GPU providers? — Pulumi. Native multi-cloud SDK with runtime decision-making in code.

Are you building a self-service ML platform? — Pulumi. Type-safe, documented infrastructure APIs that feel like libraries.

Do you need to test infrastructure before applying? — Pulumi. pytest for infrastructure. No contest.

Do you need providers for niche managed services (specific GPU operators, niche ML platforms)? — Terraform. Registry ecosystem is deeper and more mature.

Conclusion

Neither Terraform nor Pulumi is the universal right answer for AI infrastructure. The decision is contextual — it depends on your team's existing skills, the dynamic nature of your workloads, and whether you need to embed infrastructure provisioning inside ML pipelines.

Terraform wins when your infrastructure is relatively static, your team has existing Terraform expertise, and you need the depth of the Terraform Registry provider ecosystem. It is the industry standard for a reason, and for base infrastructure layers (VPC, IAM, core Kubernetes), it remains the cleanest choice.

Pulumi wins when your AI workloads are dynamic and complex, your team writes Python or TypeScript, and you want infrastructure that can be tested, embedded in ML pipelines, and extended with real programming logic. The ability to write infrastructure in the same language as your training pipelines removes an entire category of friction.

The most sophisticated AI platforms use both — Terraform for the static base, Pulumi for the dynamic workload layer. The two tools are not competitors; they solve different problems well. If you are building AI infrastructure from scratch, start with Terraform for the foundation and add Pulumi where the dynamic nature of AI workloads demands it.

The IaC layer is foundational to everything that comes after it. Investing time in making the right choice now — based on your team's actual situation, not ideological preferences — will pay dividends every time you provision a new training cluster or deploy a new model version.

Once the IaC layer is in place, the unit-economics question is what the choice actually costs you. The GPU cluster you provision through either tool will dominate the per-token cost of any model serving workload, and the easiest way to model that cost before you commit to a cluster shape is to run the actual token-cost arithmetic against your traffic. The free LLM API Cost Calculator lets you model cost-per-token across providers and quantization choices, which is the input you need when the Terraform module or Pulumi program is deciding how many GPUs to request.