XRD Field Ordering with x-ui-order#
The kubernetes-ingestor plugin supports the x-ui-order vendor extension on XRD spec fields.
When present, the plugin uses these annotations to control the order in which fields appear in
the generated Backstage scaffolder template.
How it works#
During template generation the plugin processes every XRD version's openAPIV3Schema.
For the top-level spec properties it applies the following rules:
- Fields that carry an
x-ui-order: <number>annotation are placed first, sorted in ascending numeric order. - Fields without
x-ui-orderare appended after the ordered fields, sorted alphabetically by key name. - If no field in a spec carries
x-ui-order, the original schema order is preserved unchanged.
For nested fields (array items and inline objects) the plugin generates a
ui:order
array in the uiSchema so the Backstage form renderer respects the intended order:
arrayfield →items['ui:order']is set to[...orderedKeys, '*']objectfield →field['ui:order']is set to[...orderedKeys, '*']
The trailing '*' wildcard ensures any extra field not listed explicitly is still rendered.
Example XRD#
Below is a trimmed CompositeResourceDefinition for a generic compute deployment that
demonstrates x-ui-order on both top-level spec fields and nested array-item properties.
---
apiVersion: apiextensions.crossplane.io/v2
kind: CompositeResourceDefinition
metadata:
annotations:
terasky.backstage.io/add-to-catalog: "true"
name: commoncustomdeployments.infra.example.com
spec:
group: infra.example.com
scope: Cluster
names:
kind: CommonCustomDeployment
plural: commoncustomdeployments
shortNames:
- ccd
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
required:
- spec
properties:
spec:
type: object
description: Desired state of CommonCustomDeployment.
properties:
# ── ordered top-level fields ──────────────────────────────────
stateful:
type: boolean
x-ui-order: 1
default: false
description: Stateful naming mode. Upgrade rollout is disabled when true.
replicas:
type: integer
x-ui-order: 2
default: 1
description: Number of base machine replicas.
os:
type: string
x-ui-order: 3
description: Base operating-system image key.
size:
type: string
x-ui-order: 4
description: Instance size / service offering.
enum:
- vm.xs
- vm.s
- vm.m
- vm.l
- vm.xl
network:
type: string
x-ui-order: 5
default: k8s
description: Network key from environment map.
enum:
- k8s
- app
exposureType:
type: string
x-ui-order: 6
default: None
description: Exposure type for service ports.
enum:
- LoadBalancer
- None
affinity:
type: string
x-ui-order: 7
default: None
description: Scheduling affinity rule.
enum:
- host anti-affinity
- host affinity
- None
disks:
type: array
x-ui-order: 8
description: List of additional data disks.
items:
type: object
required:
- size
- name
properties:
name:
type: string
size:
type: integer
additionalNICNetworks:
type: array
x-ui-order: 9
description: Additional NIC networks (max 2).
default: []
maxItems: 2
items:
type: string
enum:
- ingress
- egress
# ── nested x-ui-order on array items ─────────────────────────
ports:
type: array
x-ui-order: 10
description: Ports exposed via load balancer rules.
items:
type: object
properties:
publicPort:
type: integer
x-ui-order: 1
description: Exposed public VIP port.
privatePort:
type: integer
x-ui-order: 2
description: Target port on instance.
protocol:
type: string
x-ui-order: 3
description: L4 protocol for port forwarding.
enum:
- tcp
- udp
# ── field without x-ui-order (appended alphabetically) ────────
tags:
type: array
description: Arbitrary string tags for grouping.
items:
type: string
What the plugin generates#
Given the XRD above the plugin produces the following for the Resource Spec step of the
scaffolder template:
| Position | Field | Reason |
|---|---|---|
| 1 | stateful |
x-ui-order: 1 |
| 2 | replicas |
x-ui-order: 2 |
| 3 | os |
x-ui-order: 3 |
| 4 | size |
x-ui-order: 4 |
| 5 | network |
x-ui-order: 5 |
| 6 | exposureType |
x-ui-order: 6 |
| 7 | affinity |
x-ui-order: 7 |
| 8 | disks |
x-ui-order: 8 |
| 9 | additionalNICNetworks |
x-ui-order: 9 |
| 10 | ports |
x-ui-order: 10 |
| 11 | tags |
no x-ui-order → appended alphabetically |
For the ports array the plugin also injects ui:order into the array-item schema:
"ports": {
"type": "array",
"items": {
"ui:order": ["publicPort", "privatePort", "protocol", "*"]
}
}
This causes the scaffolder form to render each port row with the columns in the intended order instead of the schema-declaration order.
Rules summary#
| Scenario | Behaviour |
|---|---|
All spec fields have x-ui-order |
Sorted ascending by value |
| Mix of ordered and unordered fields | Ordered first, then unordered alphabetically |
No spec field has x-ui-order |
Original schema order preserved |
Array item properties have x-ui-order |
items['ui:order'] array injected |
Object properties have x-ui-order |
field['ui:order'] array injected |
Nested fields have no x-ui-order |
No ui:order injected, schema order used |
Notes#
x-ui-ordermust be a number (integer or float). String values are ignored.- The feature only applies to the
specobject of the XRD schema. Other top-level properties (status,metadata, etc.) are not affected. - The trailing
'*'wildcard in generatedui:orderarrays ensures fields added to the CRD after template generation are still rendered in the form. x-ui-orderis a vendor extension and is not part of the Kubernetes CRD validation; it is stripped from the CRD by the API server and only used at template-generation time by this plugin.