Importing a Motif

3 min read

Motifs are imported at the CRD entry level inside a Katalog, via the imports: field. Each import declares the source and binds CR field values to the Motif’s inputs via with:.


Basic import

spec:
  crds:
    database:
      apiTypes:
        group: apps.example.io
        version: v1
        kind: Database
      imports:
        - motif: oci://ghcr.io/orkspace/patterns/motifs/postgres:v0.1.0
          with:
            image: "{{ .spec.image }}"
            volumeSize: "{{ .spec.storage | default \"10Gi\" }}"
            replicas: "{{ .spec.replicas | default \"1\" }}"

Import sources

FormExample
Local filemotif: ./motifs/postgres/motif.yaml
OCI registrymotif: oci://ghcr.io/orkspace/patterns/motifs/postgres:v0.1.0
Git URLmotif: https://github.com/myorg/postgres-motif@main
Orkestra Registry shorthandmotif: [email protected] (resolved via ORK_REGISTRY)
imports:
  # Local — development and testing
  - motif: ./motifs/postgres/motif.yaml
    with:
      image: "postgres:16"

  # OCI — versioned, immutable, production-safe
  - motif: oci://ghcr.io/orkspace/patterns/motifs/postgres:v0.1.0
    oci: true
    with:
      image: "{{ .spec.postgresImage }}"
      volumeSize: "{{ .spec.storage }}"

  # Git
  - motif: https://github.com/myorg/postgres-motif@main
    with:
      image: "{{ .spec.postgresImage }}"

imports field reference

FieldRequiredDescription
motifyesFile path, OCI reference, Git URL, or registry shorthand.
ocinotrue to pull via OCI/ORAS protocol.
versionnoExplicit version (tag, branch, SHA). Ignored when @ shorthand is used in motif. Defaults to latest (OCI) or main (Git).
authnoRegistry credentials. Same auth model as imports.files in a Komposer.
withnoInput bindings. Values are Go templates evaluated in the CR reconcile context.

with: binding rules

with: maps Motif input names to Go template expressions evaluated against the CR being reconciled.

with:
  # CR field reference
  image: "{{ .spec.postgresImage }}"

  # With default fallback
  volumeSize: "{{ .spec.storage | default \"10Gi\" }}"

  # Literal value — no template needed
  enableUI: "false"

  # Composed value
  passwordSecretName: "{{ .metadata.name }}-secrets"
  • Required inputs not in with: → validation error at startup.
  • Optional inputs not in with: → the Motif’s default is used.
  • with: values are evaluated at reconcile time, not at load time.

Composing multiple Motifs

A CRD entry can import any number of Motifs. Each is independent — resources do not conflict when each uses {{ .metadata.name }} as a prefix.

spec:
  crds:
    platform:
      apiTypes:
        group: platform.example.io
        version: v1
        kind: Platform
      imports:
        - motif: oci://ghcr.io/orkspace/patterns/motifs/postgres:v0.1.0
          oci: true
          with:
            image: "{{ .spec.database.image }}"
            volumeSize: "{{ .spec.database.storage }}"

        - motif: oci://ghcr.io/orkspace/patterns/motifs/redis:v0.1.0
          oci: true
          with:
            image: "{{ .spec.cache.image }}"
            volumeSize: "{{ .spec.cache.storage }}"

      # The Katalog's own resources alongside the imported Motifs
      operatorBox:
        deployments:
          - name: "{{ .metadata.name }}-api"
            image: "{{ .spec.apiImage }}"
            reconcile: true

Resources from all imports are merged with operatorBox in declaration order. The operatorBox block wins on name conflict.


Motif nesting

A Motif can itself import other Motifs. A postgres-with-backup Motif could import the base postgres Motif and add a backup CronJob on top.

# In postgres-with-backup/motif.yaml
apiVersion: orkestra.orkspace.io/v1
kind: Motif
metadata:
  name: postgres-with-backup

inputs:
  - name: image
    default: "postgres:latest"
  - name: backupSchedule
    default: "0 2 * * *"

imports:
  - motif: oci://ghcr.io/orkspace/patterns/motifs/postgres:v0.1.0
    with:
      image: "{{ .inputs.image }}"

resources:
  cronJobs:
    - name: "{{ .metadata.name }}-backup"
      schedule: "{{ .inputs.backupSchedule }}"
      image: "postgres:latest"
      command: ["pg_dump"]

Real example — deployment-stack Katalog

The deployment-stack pattern in the Orkestra Registry is a Katalog that imports a single Motif and passes all CR spec fields through with::

apiVersion: orkestra.orkspace.io/v1
kind: Katalog
metadata:
  name: deployment-stack

spec:
  crds:
    application:
      apiTypes:
        group: apps.orkestra.io
        version: v1
        kind: Application
      workers: 2
      resync: 1m
      imports:
        - motif: oci://ghcr.io/orkspace/patterns/motifs/deployment-stack:v0.1.0
          with:
            name: "{{ .metadata.name }}"
            namespace: "{{ .metadata.namespace }}"
            image: "{{ .spec.image }}"
            port: "{{ .spec.port }}"
            replicas: "{{ .spec.replicas }}"
            maxReplicas: "{{ .spec.maxReplicas }}"
            resourceProfile: "{{ .spec.resourceProfile }}"
            host: "{{ .spec.host }}"

Try it:

ork init --pack advanced
cd advanced/16-custom-resources/06-full-platform-composition
ork run -f katalog.yaml
kubectl apply -f cr-small.yaml