Infrastructure as Code has been around for a while, but it’s often a bottleneck for developers. They have to file tickets, wait for SREs to provision resources, and then hope they got the configuration right. Crossplane, and specifically its concept of XRDs (Composed Resources), offers a way to democratize infrastructure provisioning by letting developers define and manage their own resources directly.

Imagine you’re building a web application and you need a PostgreSQL database. Normally, you’d open a ticket: "I need a PostgreSQL instance with these specs." An SRE would then use Terraform, Pulumi, or manual CLI commands to create it, apply security rules, and hand you back the connection string. This process is slow and error-prone, especially when you need multiple databases or frequent changes.

Crossplane XRCs flip this model. Instead of waiting for an SRE, you, the developer, can define a CompositeResourceDefinition (XRD) that describes a kind of infrastructure you want. For example, you might define a CompositePostgreSQLInstance XRD. This XRD isn’t a real database; it’s a blueprint.

Here’s what that blueprint might look like in YAML:

apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: compositedatabaseinstances.database.example.com
spec:
  group: database.example.com
  names:
    kind: CompositeDatabaseInstance
    plural: compositedatabaseinstances
  versions:
  - name: v1
    served: true
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              parameters:
                type: object
                properties:
                  storageGB:
                    type: integer
                    description: "Size of the database in GB"
                  instanceClass:
                    type: string
                    description: "Instance type for the database"
              compositionSelector:
                matchLabels:
                  provider: aws # Or gcp, azure, etc.
                  tier: production
            required:
            - parameters

This CompositeResourceDefinition (XRD) tells Crossplane about a new custom resource called CompositeDatabaseInstance. It specifies that this resource has a spec with parameters like storageGB and instanceClass, and crucially, it uses a compositionSelector to find the actual how-to for provisioning this resource.

The "how-to" is defined in a Composition. A Composition is a Crossplane resource that tells Crossplane how to provision underlying infrastructure when a CompositeResource (like our CompositeDatabaseInstance) is created. It maps the developer-friendly parameters from the CompositeResource to the specific resources of a cloud provider.

Here’s a Composition that fulfills our CompositeDatabaseInstance XRD, targeting AWS RDS:

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: rds-postgres-production
  labels:
    provider: aws
    tier: production
spec:
  compositeTypeRef:
    kind: CompositeDatabaseInstance
    apiVersion: database.example.com/v1
  resources:
    - name: rdsinstance
      base:
        apiVersion: rds.aws.upbound.io/v1beta1
        kind: Instance
        spec:
          region: us-east-1
          skipFinalizer: false
          writeConnectionSecretToRef:
            namespace: crossplane-system
      patches:
        - fromFieldPath: spec.parameters.storageGB
          toFieldPath: spec.allocatedStorage
        - fromFieldPath: spec.parameters.instanceClass
          toFieldPath: spec.dbInstanceClass
        - fromFieldPath: spec.parameters.storageGB
          toFieldPath: spec.maxAllocatedStorage # Example of mapping

This Composition says: "When someone creates a CompositeDatabaseInstance and it matches my labels (e.g., provider: aws, tier: production), create an AWS RDS Instance. Map the spec.parameters.storageGB from the CompositeDatabaseInstance to the spec.allocatedStorage of the RDS Instance, and spec.parameters.instanceClass to spec.dbInstanceClass."

Now, the developer can create an instance of their CompositeDatabaseInstance custom resource:

apiVersion: database.example.com/v1
kind: CompositeDatabaseInstance
metadata:
  name: my-app-db
spec:
  parameters:
    storageGB: 100
    instanceClass: db.t3.medium

When Crossplane sees this CompositeDatabaseInstance, it looks for a Composition that matches its spec.compositionSelector. It finds rds-postgres-production, and then uses the resources and patches defined within it to create an actual AWS RDS Instance. The connection details for this RDS instance will be automatically populated into a Kubernetes Secret, usually named something like rdsinstance-my-app-db, which the developer can then use in their application.

The magic here is that the developer never had to touch AWS CLI, Terraform, or know the exact RDS Instance API. They’re working with a higher-level abstraction that they (or their platform team) defined. The Composition acts as the bridge between the developer’s desired state and the cloud provider’s reality.

What most people miss is that the CompositeResourceDefinition (XRD) and Composition are themselves Kubernetes Custom Resources. Crossplane is just extending the Kubernetes API. This means you can use standard Kubernetes tools like kubectl to manage your infrastructure definitions. You can version control your XRDs and Compositions in Git, apply them using kubectl apply -f, and treat your infrastructure blueprints like any other application code. This also means you can build sophisticated policies and workflows around them using Kubernetes admission controllers or GitOps tools.

Once your CompositeDatabaseInstance is created and the underlying RDS instance is provisioned, the next logical step is to integrate it directly with your application deployment.

Want structured learning?

Take the full Crossplane course →