Skip to main content
  1. Docs
  2. Infrastructure as Code
  3. Comparisons
  4. Crossplane

Pulumi vs. Crossplane

    Pulumi and Crossplane are both declarative infrastructure as code tools that provision resources across clouds and SaaS platforms, but they take different architectural approaches. Pulumi lets you define infrastructure in general-purpose languages (Python, TypeScript, JavaScript, Go, C#, Java, or YAML) and runs through a CLI or an embeddable SDK. Crossplane extends Kubernetes into a control plane: infrastructure is defined as Kubernetes resources in YAML and reconciled continuously by controllers running inside a cluster.

    This page covers what each tool is, a feature-by-feature comparison, the most important differences in detail, and the available paths for adopting Pulumi alongside or instead of Crossplane.

    What is Pulumi?

    Pulumi is an infrastructure as code platform for provisioning and managing resources across any cloud or SaaS platform. Pulumi programs are written in general-purpose programming languages — Python, TypeScript, JavaScript, Go, .NET, and Java — as well as YAML. The Pulumi Registry covers all major clouds, including first-party native providers that are generated from upstream API schemas for same-day coverage of new platform features. The Pulumi CLI and SDKs are open source under the Apache 2.0 license. Pulumi Cloud is the commercial product that adds managed state, secrets, RBAC, audit logs, policy management, and other features for running Pulumi at organizational scale.

    For users coming from Crossplane, Pulumi does not require a Kubernetes cluster to run, but it works well with Kubernetes when you need it: the first-party Kubernetes provider is generated from the upstream Kubernetes API schema and can manage any resource type, including Custom Resource Definitions (CRDs) — so a Pulumi program can install and operate Crossplane itself.

    What is Crossplane?

    Crossplane is an open-source control plane framework that extends Kubernetes to provision and manage infrastructure across clouds and SaaS platforms. It was created by Upbound and is a graduated project of the Cloud Native Computing Foundation (CNCF). Crossplane is licensed under the Apache License 2.0.

    With Crossplane, infrastructure is expressed as Kubernetes resources written in YAML and applied to a cluster, where controllers continuously reconcile the actual state of cloud resources toward the declared state. Cloud and service support comes from Crossplane providers, many of which are generated from Terraform providers using the Upjet code-generation framework; official providers exist for AWS, Azure, and Google Cloud. Reusable abstractions are built with Composite Resource Definitions (XRDs) and Compositions. State lives in the Kubernetes cluster’s etcd datastore rather than in a separate state file.

    Crossplane v2, released in August 2025, made composite and managed resources namespaced by default, removed the separate “claim” concept, replaced patch-and-transform composition with composition functions, and allowed compositions to include any Kubernetes resource — not just Crossplane-managed infrastructure. Crossplane itself has no commercial tier; managed control planes and an enterprise distribution are offered by Upbound.

    Detailed comparison

    FeaturePulumiCrossplane
    Language supportPython, TypeScript, JavaScript, Go, C#, Java, and YAML — general-purpose languages with familiar syntax for loops, conditionals, and abstractionsKubernetes YAML manifests for declaring resources; Go is used to build providers and composition functions
    Cloud and service supportPulumi Registry of packages, including bridged, native, parameterized, and dynamic providers; first-party native providers for Kubernetes and Azure Native generated from upstream API schemas; any OpenTofu or Terraform provider can be generated into a Pulumi SDK with pulumi package add terraform-provider <name>Crossplane providers installed into the cluster as packages; official AWS, Azure, and Google Cloud providers plus community providers, many generated from Terraform providers via Upjet
    Transpiled to another format?No — programs run directly in their host languageNo — YAML manifests are reconciled directly by Crossplane controllers
    State managementManaged by Pulumi Cloud by default; self-managed backends include Amazon S3, Azure Blob Storage, Google Cloud Storage, local files, and othersStored in the Kubernetes cluster’s etcd datastore as the status of resource objects; no separate state file
    Secrets managementEncrypted in transit and at rest in the state file by default, with per-stack encryption keys; pluggable KMS providers (AWS KMS, Azure Key Vault, Google Cloud KMS, HashiCorp Vault)Kubernetes Secrets for provider credentials and connection details; secret data is not encrypted as a first-class primitive and relies on the cluster’s secret-handling configuration
    Execution modelLocal CLI, programmatic via Automation API, or remote runs in Pulumi DeploymentsCentralized: controllers run inside a Kubernetes cluster and reconcile resources continuously; changes are applied with kubectl or a GitOps workflow
    Rollback on failed operationFailed updates leave the stack in a partially-updated state; subsequent pulumi up runs reconcile toward the desired state, and you can roll forward by reverting program codeNo transactional rollback; controllers retry continuously until resources converge, and you roll forward by reapplying corrected manifests
    Programmatic API for tools and platformsAutomation API — a programmatic SDK for building custom CLIs, internal developer platforms, and services that drive up, preview, and destroy without shelling out to the Pulumi CLIThe Kubernetes API itself is the programmatic interface; tools and platforms interact with Crossplane by creating and reading Kubernetes resources
    Modularity and reuseComponent Resources authored in any supported language; Pulumi Packages let a component written in one language be consumed from any Pulumi language; language-native package managers (npm, PyPI, NuGet, Maven, Go modules); and the Pulumi Registry for publicly available packagesComposite Resource Definitions (XRDs) and Compositions define reusable APIs; composition functions add programmatic logic; packaged and distributed as Crossplane configuration packages
    Import existing resourcespulumi import and the import resource option, both of which generate code in your languageExisting resources are brought under management by applying a manifest with the appropriate external-name annotation so the controller adopts them
    Policy as codePulumi Policies — open source, with rules written in Python, TypeScript, or Open Policy Agent Rego; Pulumi Cloud commercial plans add centralized policy management plus Pulumi-maintained policy packs for compliance frameworks like CIS, HITRUST, NIST, and PCI DSSNo built-in policy-as-code; teams typically use Kubernetes admission-control tools such as Open Policy Agent Gatekeeper or Kyverno to enforce policy on Crossplane resources
    Open sourceYes — Apache License 2.0Yes — Apache License 2.0
    Commercial optionPulumi CloudNone from the Crossplane project itself; managed control planes and an enterprise distribution are offered by Upbound

    Key differences

    Language support and the authoring experience

    Crossplane infrastructure is declared in Kubernetes YAML manifests. The model is fully declarative and integrates naturally with kubectl and GitOps tooling, but YAML on its own has no loops, conditionals, or types; programmatic logic for reusable APIs is added through composition functions, which are written in a general-purpose language and run as part of the reconciliation pipeline. Pulumi programs are written directly in general-purpose languages, so authors get loops, conditionals, classes, package management, IDE features (autocomplete, type checking, refactoring, go-to-definition), and the testing frameworks that already exist in those ecosystems. Pulumi also supports YAML for users who prefer a markup format.

    Cloud and service coverage

    Both tools target broadly the same set of clouds and SaaS platforms but reach them differently. Crossplane installs providers into the cluster as packages; the official AWS, Azure, and Google Cloud providers, along with many community providers, are generated from Terraform providers using the Upjet framework. Pulumi pulls from the Pulumi Registry, which includes bridged, native, parameterized, and dynamic providers. Pulumi also maintains native providers for Kubernetes and Azure Native, generated directly from each platform’s API schema for same-day coverage of new resources. When a provider is not packaged in the Pulumi Registry, the Any Terraform Provider feature generates a typed Pulumi SDK from any provider in the OpenTofu or Terraform registry.

    Execution model and reconciliation

    This is the most fundamental difference between the two tools. Crossplane runs as a set of controllers inside a Kubernetes cluster. Once a manifest is applied, the controllers reconcile continuously: they detect drift and correct it automatically without a person running a command, which makes Crossplane well suited to always-on, GitOps-driven platforms. The trade-off is that Crossplane requires a running Kubernetes cluster as part of its operational footprint.

    Pulumi runs on demand. Changes are applied through the local CLI, programmatically through the Automation API, or remotely through Pulumi Deployments, and pulumi preview shows the exact set of changes before they are made. Drift is detected when you run pulumi preview or pulumi refresh rather than corrected continuously. Pulumi does not require any cluster or long-running service to operate, though Pulumi Cloud and Pulumi Deployments are available when you want a managed service. Neither tool performs a transactional rollback on a failed operation: Pulumi leaves the stack partially updated and reconciles on the next run, while Crossplane’s controllers retry until resources converge.

    Secrets handling

    Pulumi treats secrets as a first-class primitive. Values marked as secrets are encrypted in transit and at rest in the state file, anything derived from a secret is also encrypted, and each stack has its own encryption key. The default encryption provider can be replaced with AWS KMS, Azure Key Vault, Google Cloud KMS, or HashiCorp Vault. Crossplane stores provider credentials and resource connection details as standard Kubernetes Secrets; how strongly those are protected depends on the cluster’s secret-handling configuration (for example, etcd encryption at rest or an external secrets store), rather than being encrypted by Crossplane itself.

    Policy as code

    Pulumi Policies is open source and free. Policies can be written in Python, TypeScript, or Open Policy Agent Rego, and Pulumi Cloud adds centralized management, policy groups, and enforcement across stacks. Pulumi Cloud commercial plans also include Pulumi-maintained policy packs for common compliance frameworks (CIS, HITRUST, NIST, and PCI DSS). Crossplane has no built-in policy-as-code feature; because Crossplane resources are Kubernetes objects, teams typically enforce policy with Kubernetes admission controllers such as Open Policy Agent Gatekeeper or Kyverno.

    Modularity and reuse

    Crossplane’s reuse model is the Composite Resource Definition (XRD) and Composition: an XRD defines a new high-level API, and a Composition specifies the resources that back it, with composition functions supplying programmatic logic. These abstractions are packaged and distributed as configuration packages and consumed as Kubernetes resources. Pulumi’s Component Resources are runtime objects with explicit parent/child relationships, so a component and the resources inside it form a coherent unit in plan output, deletion, and state. Components can be authored in one language and consumed from any other supported language by publishing them as a Pulumi Package, and they are distributed through language-native package managers and the Pulumi Registry.

    Automation API

    The Automation API lets a host application drive Pulumi without shelling out to the CLI. Practical uses include embedding stack creation in a SaaS product, building an internal developer platform that provisions environments per team or per branch, generating ephemeral preview environments from CI, and orchestrating cross-cloud deployments where each step runs as part of a larger workflow. Crossplane exposes its functionality through the Kubernetes API instead: applications and platforms integrate with Crossplane by creating and reading Kubernetes resources, which is a natural fit for teams already building on Kubernetes APIs and controllers.

    When to choose Pulumi vs. Crossplane

    Choose Pulumi when you:

    1. Want to write infrastructure in a general-purpose language with the testing frameworks, package managers, and IDE tooling that already exist in that ecosystem.
    2. Do not want to run and operate a Kubernetes cluster as a prerequisite for managing infrastructure.
    3. Need an embeddable SDK (Automation API) to drive deployments from a host application — internal developer platforms, SaaS products, or ephemeral preview environments per pull request.
    4. Want first-class encrypted secrets with pluggable KMS providers and per-stack encryption keys.

    Choose Crossplane when you:

    1. Are standardizing on Kubernetes as a control plane and want infrastructure managed through the same API, RBAC, and GitOps workflows as your applications.
    2. Want controllers that continuously reconcile and automatically correct drift without a person running a command.
    3. Prefer to define infrastructure declaratively in YAML and consume reusable platform APIs as Kubernetes resources.

    The two can also coexist — see Adoption below.

    Adoption: coexistence, conversion, and import

    There are several common paths for adopting Pulumi alongside or in place of Crossplane, and they can be combined:

    1. Use Crossplane alongside Pulumi. Because Crossplane and its resources are Kubernetes objects, a Pulumi program using the Kubernetes provider can install Crossplane, install providers, and apply Crossplane manifests — for example with ConfigGroup or ConfigFile to apply existing YAML, or crd2pulumi to generate typed SDKs from Crossplane CRDs. This lets a team manage the cluster and bootstrap Crossplane with Pulumi while keeping Crossplane-managed resources where they are.
    2. Convert YAML with pulumi convert. pulumi convert --from kubernetes translates Kubernetes YAML manifests, including Crossplane resources, into a Pulumi program in the language of your choice.
    3. Import existing resources. pulumi import and the import resource option bring already-provisioned cloud resources under Pulumi management and generate the corresponding code in your chosen language.

    For a walkthrough of moving Kubernetes-based infrastructure to Pulumi, see Migrating from Kubernetes to Pulumi.

    Frequently asked questions

    Is Crossplane the same as Terraform?

    No. They are different tools, though they are related: many Crossplane providers are generated from Terraform providers using the Upjet framework, so they cover similar cloud APIs. The execution models differ — Terraform runs on demand through a CLI, while Crossplane runs as controllers inside a Kubernetes cluster that reconcile continuously. Crossplane uses Kubernetes YAML and the Kubernetes API rather than HCL and the Terraform CLI.

    Does Pulumi require Kubernetes?

    No. Pulumi runs as a CLI or through the Automation API and does not need a Kubernetes cluster to manage infrastructure. Crossplane, by contrast, runs its controllers inside a Kubernetes cluster, so a cluster is part of its operational footprint. Pulumi does have a first-party Kubernetes provider for teams that want to manage Kubernetes resources — including Crossplane itself — but it is optional.

    Can Pulumi deploy and manage Crossplane resources?

    Yes. Crossplane, its providers, and the custom resources it defines are all Kubernetes objects, so Pulumi’s Kubernetes provider can install Crossplane and apply Crossplane manifests. You can apply existing YAML with ConfigGroup or ConfigFile, or use crd2pulumi to generate typed SDKs from Crossplane CRDs.

    How do I migrate from Crossplane to Pulumi?

    You have options that can be combined: convert Crossplane YAML manifests with pulumi convert --from kubernetes, bring already-provisioned cloud resources under Pulumi management with pulumi import, or run both tools side by side and migrate incrementally. See Migrating from Kubernetes to Pulumi for a walkthrough.

    Is Pulumi free like Crossplane?

    The Pulumi CLI and SDKs are open source under Apache 2.0 and free to use. Pulumi Cloud has a free Individual tier and paid plans that add managed state, RBAC, audit logs, policy management, and other features for running Pulumi at organizational scale. Crossplane itself is free under Apache 2.0; managed control planes and an enterprise distribution are sold separately by Upbound.

    Next steps