on
Getting started with Crossplane composition functions: build portable, reusable cloud APIs
Crossplane is a way to treat your cloud services like Kubernetes objects: you declare a high-level API, and Crossplane stitches together provider-managed resources to satisfy it. If you’ve used Terraform modules or Helm charts, think of Crossplane’s Compositions as a way to package an opinionated, reusable infrastructure API your platform team can give developers — but driven by Kubernetes’ control loop. (docs.crossplane.io)
This article walks through a recent, practical pattern that’s great for getting started: using Composition Functions (a newer Crossplane capability) to implement reusable, environment-aware Compositions (for example, “managed PostgreSQL for dev/staging/prod”) without turning your YAML into unreadable templates. I’ll explain the concepts, show a minimal Composition-as-pipeline, and give pragmatic tips so your first experiment isn’t a headache.
Why Composition Functions?
- Compositions and XRDs (Composite Resource Definitions) let you define a custom API (an XR) and map it to one or more managed cloud resources. That separation creates a stable, platform-facing surface while the Composition controls the cloud plumbing. (docs.crossplane.io)
- Composition Functions extend Compositions by letting you run code (packaged as a function) during the composition step. Instead of trying to express complex transforms and conditionals entirely with YAML patches, you can write a small program that returns the resources the Composition should create. This makes complex transformations clearer and testable. (docs.crossplane.io)
Think of it like making music: a Composition is the song structure (verse, chorus, bridge), while a Composition Function is a synth patch or effect you plug in to shape a sound. You could try to tune every parameter by hand, but sometimes a small script or plugin gives you the expressive control you need.
How Composition Functions fit into a Composition
- A Composition can operate in “Pipeline” mode. Instead of just applying static resource templates, the Composition runs a pipeline of function steps; each step can inspect the composite resource and produce or mutate the set of managed resources to create. (docs.crossplane.io)
- Crossplane provides function runtimes and helper functions (for common transformations/patching) and you can author your own functions in languages like Go or use the KCL-based functions and community-contributed examples. You can build, package, and distribute functions as Crossplane packages (OCI images) and reference them from a Composition. (docs.crossplane.io)
A simple getting-started recipe (conceptual)
- Install Crossplane and the cloud provider providers you need (AWS, GCP, Azure, or the Crossplane provider for managed Postgres). The official Crossplane docs have step-by-step installation instructions for the control plane and provider configuration. (docs.crossplane.io)
- Define an XRD that represents your platform API — e.g., CompositePostgresInstance with fields for size, storage, environment, and credentials target. This XRD is the contract developers will request. (docs.crossplane.io)
- Create a Composition in Pipeline mode that references a function pipeline. The pipeline runs one or more functions that can:
- decide which cloud provider resource to create based on the “environment” field (dev → cheaper, prod → managed DB),
- generate small derived names and labels,
- attach connection secret wiring and RBAC rules. The Composition’s pipeline lets you orchestrate that logic in code rather than complex YAML patches. (docs.crossplane.io)
- Implement or reuse a Composition Function. Start with the community function “patch-and-transform” or a simple Go function example from the Crossplane docs, then iterate. The docs note you can develop and test a function without a running Crossplane cluster — helpful for rapid feedback. (docs.crossplane.io)
- Create a composite resource (an instance of your XRD). Crossplane will run the Composition pipeline and materialize the managed cloud resources and secrets that implement your custom API. Inspect the composite resource’s status and generated resource refs to debug.
Minimal Composition YAML (illustrative)
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: composite-postgres-composition
spec:
compositeTypeRef:
apiVersion: database.example.org/v1
kind: CompositePostgresInstance
mode: Pipeline
pipeline:
- step: choose-and-render
functionRef:
name: function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: postgres
base:
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
spec:
forProvider:
instanceClass: db.t3.medium
This snippet shows a Composition in Pipeline mode that calls a function named function-patch-and-transform. The function receives the composite resource and a base “resource template” and returns the rendered managed resources. In practice you’d add conditionals or a separate step to choose different provider resources for different environments. (docs.crossplane.io)
Where to find examples and community patterns
- Crossplane’s official docs and guides include “Get started with Composition” and function-writing guides with examples. Those pages are the most authoritative reference for Composition syntax and function lifecycle. (docs.crossplane.io)
- The community and vendor blueprints (for example, Amazon’s Crossplane patterns and nested compositions) provide concrete examples for multi-resource patterns and nested compositions: useful if you want a real-world application that creates networking, IAM, and a database in a single XR. (awslabs.github.io)
Practical tips and pitfalls
- Start small: model a simple API (PG instance with size + environment) and iterate. It’s much easier to add capabilities to a clean XRD than to untangle a big one later.
- Use function packages for complexity: if your transform logic is more than a few patches, write a function. That logic becomes testable and versionable (packaged as OCI), instead of being spread across nested YAML patches.
- Observe Composition revisions: Crossplane tracks Composition revisions — treat Composition changes like code changes and roll them out carefully. The docs show how Crossplane creates composition revisions so producers can safely update behavior. (docs.crossplane.io)
- Don’t give Crossplane more cloud permissions than necessary: a wide permission span is common in experiments but consider least-privilege for production control planes.
A balanced note Crossplane’s model is powerful but different from traditional IaC. If you’re used to imperative tooling or single-team ownership of infra, the mental model of platform-defined APIs and a control plane will require some organizational shifts (ownership, RBAC, and testing). But once you land the model, Composition Functions let platform teams keep policy and complexity in a maintainable place while developers consume a simple Kubernetes-style API.
Closing chord If you want a practical first experiment: define a tiny CompositePostgresInstance XRD, author a Pipeline Composition that uses the patch-and-transform function to produce an RDS or CloudSQL resource depending on an environment field, and create a composite resource for “dev”. Watch Crossplane create the managed resource and the connection secret — it’s a satisfying “plug in the amp and hear the note” moment.
Sources for further reading
- Crossplane Compositions and Composite Resource Definitions (official docs). (docs.crossplane.io)
- Crossplane composition functions guide and production notes. (docs.crossplane.io)
- Guide on writing composition functions in Go (how to build/test functions locally). (docs.crossplane.io)
- AWS Crossplane patterns and nested compositions for example blueprints. (awslabs.github.io)
Happy composing — think of Compositions as your band’s arrangement and functions as the pedals that make the sound yours.