Why Compositions
Individual Managed Resources give you fine-grained cloud control, but they expose too much complexity to application developers. A team requesting a database shouldn't need to specify VPC subnet IDs, security group rules, and parameter groups. Compositions solve this by defining opinionated infrastructure blueprints.
- Abstract complexity — Hide VPC, subnet, security group details behind a simple "give me a database" API
- Enforce standards — Compositions embed organizational requirements (encryption, tagging, networking) that can't be bypassed
- Enable self-service — Dev teams request infrastructure through simple Claims without cloud expertise
CompositeResourceDefinition (XRD)
An XRD defines the API schema — what parameters platform consumers can set. It registers a new CRD in the cluster (e.g., XDatabase) with a validated OpenAPI schema:
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.platform.example.com
spec:
group: platform.example.com
names:
kind: XDatabase
plural: xdatabases
claimNames:
kind: Database
plural: databases
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
parameters:
type: object
properties:
engine:
type: string
enum: ["postgres", "mysql"]
description: "Database engine type"
size:
type: string
enum: ["small", "medium", "large"]
description: "Instance size class"
region:
type: string
default: "us-east-1"
required:
- engine
- size
required:
- parameters
# Apply the XRD
kubectl apply -f xrd-database.yaml
# Verify the new CRDs are registered
kubectl get crd | grep platform.example.com
# xdatabases.platform.example.com 2026-06-06T10:00:00Z
# databases.platform.example.com 2026-06-06T10:00:00Z
# The XRD creates both:
# - XDatabase (cluster-scoped composite resource)
# - Database (namespace-scoped claim)
Composition
A Composition wires the XRD to actual Managed Resources. It specifies which cloud resources to create and how to map parameters from the composite resource to each underlying resource:
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: xdatabases.aws.platform.example.com
labels:
provider: aws
engine: postgres
spec:
compositeTypeRef:
apiVersion: platform.example.com/v1alpha1
kind: XDatabase
resources:
- name: rds-instance
base:
apiVersion: rds.aws.upbound.io/v1beta2
kind: Instance
spec:
forProvider:
engine: postgres
engineVersion: "15"
publiclyAccessible: false
storageEncrypted: true
storageType: gp3
skipFinalSnapshot: true
tags:
ManagedBy: crossplane
Platform: "true"
providerConfigRef:
name: default
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.region
toFieldPath: spec.forProvider.region
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.size
toFieldPath: spec.forProvider.instanceClass
transforms:
- type: map
map:
small: db.t3.micro
medium: db.t3.medium
large: db.r6g.large
Patches
Patches are the glue between composite resources and managed resources. They copy, transform, and compute values flowing between the API layer and the infrastructure layer.
FromCompositeFieldPath (composite → managed), ToCompositeFieldPath (managed → composite status), CombineFromComposite (merge multiple fields), and FromEnvironmentFieldPath (from EnvironmentConfig).
# Advanced patch examples within a Composition resource
patches:
# Simple field copy
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.region
toFieldPath: spec.forProvider.region
# Map transform (enum to cloud value)
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.size
toFieldPath: spec.forProvider.instanceClass
transforms:
- type: map
map:
small: db.t3.micro
medium: db.t3.medium
large: db.r6g.large
# String format (combine values)
- type: CombineFromComposite
combine:
variables:
- fromFieldPath: metadata.name
- fromFieldPath: spec.parameters.engine
strategy: string
string:
fmt: "%s-%s-sg"
toFieldPath: spec.forProvider.name
# Propagate status back to composite
- type: ToCompositeFieldPath
fromFieldPath: status.atProvider.endpoint
toFieldPath: status.endpoint
Testing Compositions
Crossplane provides a beta render command that locally renders a Composition against an XR (composite resource) input, showing exactly which Managed Resources would be created without touching any cloud API:
# Create a test XR input file (xr.yaml)
cat <<EOF > xr.yaml
apiVersion: platform.example.com/v1alpha1
kind: XDatabase
metadata:
name: test-db
spec:
parameters:
engine: postgres
size: medium
region: eu-west-1
EOF
# Render the Composition locally
crossplane beta render xr.yaml composition.yaml functions.yaml
# Output shows the rendered Managed Resources with all patches applied
# Verify instanceClass=db.t3.medium, region=eu-west-1, etc.
# Validate XRD schema against an input
crossplane beta validate xrd.yaml xr.yaml
Exercises
XNetwork that exposes parameters for cidrBlock (string) and availabilityZones (integer, 2 or 3). Write a Composition that creates a VPC and the specified number of subnets. Use a map transform to convert AZ count to subnet CIDR ranges.
CombineFromComposite patches to generate unique names for each resource. Add a ToCompositeFieldPath patch that exposes the RDS endpoint in the composite's status.
crossplane beta render to test your Composition locally. Create three different XR inputs (small/postgres, medium/mysql, large/postgres) and verify the rendered output has the correct instance classes, engine versions, and generated names. Fix any patch errors the render reveals.
Key Takeaways & Next Steps
- Compositions combine multiple Managed Resources into reusable infrastructure blueprints
- XRDs define the simplified API schema that platform consumers interact with
- Patches copy and transform values between the composite API and underlying resources
- Map transforms convert human-friendly enums (small/medium/large) to cloud-specific values
crossplane beta renderenables local testing without cloud API calls
Next in the Series
In Part 3: Claims & GitOps Integration, we'll use namespace-scoped Claims for self-service infrastructure requests and integrate Crossplane with Flux and ArgoCD for GitOps-driven provisioning.