A standalone tool for visualizing the differences between Crossplane resources in YAML files and their resulting state
when applied to a live Kubernetes cluster. Similar to kubectl diff but with specific enhancements for Crossplane
resources, particularly Composite Resources (XRs) and their composed resources.
The crossplane-diff tool helps you:
- Preview changes before applying Crossplane resources to a cluster
- Visualize differences at multiple levels: both the XR itself and all downstream composed resources
- Analyze composition impact showing how composition changes affect existing XRs in the cluster
- Support complex compositions including functions, requirements, and environment configurations
- Handle both Crossplane v1 and v2 resource definitions, including namespaced composite resources
- Detect resources that would be removed by your changes
Download the latest release from the releases page.
git clone https://github.com/crossplane-contrib/crossplane-diff.git
cd crossplane-diff
go build -o crossplane-diff ./cmd/diff# Show changes that would result from applying an XR from a file
crossplane-diff xr xr.yaml
# Show changes from stdin
cat xr.yaml | crossplane-diff xr -
# Process multiple files
crossplane-diff xr xr1.yaml xr2.yaml xr3.yaml
# Show changes in a compact format with minimal context
crossplane-diff xr xr.yaml --compact
# Disable color output
crossplane-diff xr xr.yaml --no-color# Show impact of updated composition on all XRs using it
crossplane-diff comp updated-composition.yaml
# Show impact of multiple composition changes
crossplane-diff comp comp1.yaml comp2.yaml comp3.yaml
# Show impact only on XRs in a specific namespace
crossplane-diff comp updated-composition.yaml -n production
# Include XRs with Manual update policy (pinned revisions)
crossplane-diff comp updated-composition.yaml --include-manualcrossplane-diff xr [<files> ...] [flags]
Arguments:
[<files> ...] YAML files containing Crossplane resources to diff.
Flags:
-h, --help Show context-sensitive help.
--verbose Print verbose logging statements.
--no-color Disable colorized output.
--compact Show compact diffs with minimal context.
--max-nested-depth=10 Maximum depth for nested XR recursion.
--timeout=1m How long to run before timing out.
--qps=0 Maximum QPS to the API server.
--burst=0 Maximum burst for throttle.
Note: XR namespaces are read directly from the YAML files being diffed, not from command-line flags.
crossplane-diff comp [<files> ...] [flags]
Arguments:
[<files> ...] YAML files containing updated Composition(s).
Flags:
-h, --help Show context-sensitive help.
--verbose Print verbose logging statements.
--no-color Disable colorized output.
--compact Show compact diffs with minimal context.
--max-nested-depth=10 Maximum depth for nested XR recursion.
--timeout=1m How long to run before timing out.
--qps=0 Maximum QPS to the API server.
--burst=0 Maximum burst for throttle.
-n, --namespace="" Namespace to find XRs (empty = all namespaces).
--include-manual Include XRs with Manual update policy (default:
only Automatic policy XRs)
Note: The diff subcommand is deprecated. Use xr instead.
- A running Kubernetes cluster with Crossplane installed
kubectlconfigured to access your cluster- Appropriate RBAC permissions (see Required Permissions)
The tool performs the following steps:
- Load resources from YAML files or stdin
- Find matching compositions for each Composite Resource
- Render resources using the same composition pipeline as Crossplane
- Resolve requirements iteratively (environment configs, external resources)
- Propagate namespaces from XRs to managed resources (for Crossplane v2)
- Validate resources against their schemas and enforce scope constraints
- Calculate diffs by comparing rendered resources against current cluster state
- Display formatted output showing what would change
This tool fully supports both Crossplane v1 and v2, including:
- Cluster-scoped XRDs: Traditional cluster-wide resources
- Namespaced XRDs: Resources confined to specific namespaces for better isolation
- Automatic scope detection: Determines whether XRDs are cluster or namespace scoped
- Namespace propagation: Ensures managed resources inherit appropriate namespaces
- Scope validation: Enforces rules like "namespaced XRs cannot own cluster-scoped managed resources"
Note: Namespace information is read directly from the XR definitions in your YAML files, not from command-line flags.
The tool requires read access to:
- Crossplane definitions: XRDs, Compositions, Functions
- Crossplane runtime resources: XRs, Claims, Managed Resources
- Crossplane configuration: EnvironmentConfigs
- Kubernetes resources: CRDs, referenced resources
- Resource hierarchies: Owner references and relationships
The output follows familiar diff conventions with colorized output (unless disabled):
+++ Resource/new-resource-(generated)
+ apiVersion: nop.crossplane.io/v1alpha1
+ kind: NopResource
+ metadata:
+ name: new-resource
+ spec:
+ forProvider:
+ field: value
---
--- XNopResource/removed-resource
- apiVersion: diff.example.org/v1alpha1
- kind: XNopResource
- spec:
- coolField: goodbye!
~~~
~~~ Resource/modified-resource
metadata:
name: modified-resource
- spec:
- oldValue: something
+ spec:
+ newValue: something-else
---
Summary: 1 added, 1 modified, 1 removedThe tool prioritizes accuracy above all else:
- Never silently continues in the face of failures
- Avoids making best-guesses that could compromise accuracy
- Fails completely rather than emit potentially incorrect partial results
- Reaches extensively into the cluster for all information needed to produce accurate diffs
- Caches resources only to avoid API throttling
The tool does not take a snapshot of cluster state before processing, so changes made to the cluster during execution may affect results.
- Design Document: Comprehensive technical design and architecture
- CLAUDE.md: Instructions for Claude. Contains development principles and guidelines for LLMs.
Prerequisites:
- Go 1.24+
- Docker
- Earthly (install instructions)
- kubectl
Setup Steps:
-
Install required tools:
go install sigs.k8s.io/controller-runtime/tools/[email protected] setup-envtest use 1.30.3 # or whatever cluster version we're using now
-
Generate test manifests:
earthly +go-generate --CROSSPLANE_IMAGE_TAG=main
-
Build the project:
earthly +build
Unit and Integration Tests (fast):
cd cmd/diff
go test ./...Development Checks (linting, tests, generation):
# Run before opening any PR
earthly +reviewableEnd-to-End Tests:
# Full test matrix against multiple Crossplane versions (slower)
earthly -P +e2e-matrix
# Single E2E test against specific version
earthly +e2e --CROSSPLANE_IMAGE_TAG=main# Build binary
earthly +build
# Run linting
earthly +lint
# Generate code/manifests
earthly +generate
# All available targets
earthly --helpThe tool follows a clean layered architecture:
- Command Layer: CLI argument parsing and coordination
- Application Layer: Process orchestration and resource loading
- Domain Layer: Core diff logic, rendering, and validation
- Client Layer: Kubernetes and Crossplane API interactions
The project includes comprehensive testing:
- Unit tests: Fast, isolated component testing
- Integration tests: Using
envtestfor realistic cluster interactions - E2E tests: Full end-to-end scenarios across v1, v2-cluster, and v2-namespaced configurations
Contributions are welcome! Please see our contributing guidelines for detailed setup instructions and development workflow.
Quick Start for Contributors:
- Fork and clone the repository
- Run setup:
earthly +go-generate --CROSSPLANE_IMAGE_TAG=main - Make your changes
- Test your changes:
earthly +reviewable && earthly -P +e2e-matrix - Open a pull request
See CONTRIBUTING.md for complete guidelines and CODE_OF_CONDUCT.md for community standards.
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.