Skip to content

Composition & Wiring

A component’s deploy is a composition over capabilities, expressed in the same grammar as Ops: phases run in order, steps in a phase run sequentially unless parallel, gate pauses for a signal, and onFailure compensates. Steps wire output to input so lint can check the graph before anything runs.

deploy: [
phase("Publish", [publishImage({ from: "archive", to: "$env.registry" })]), // → @Publish.digest
phase("Apply", [cfnDeploy({ template: "archive:t.json", imageRef: "@Publish.digest" })]),
phase("Verify", [waitSteadyState({ service: "api" })]),
]

Fan-out is composition, not orchestrator knowledge

Section titled “Fan-out is composition, not orchestrator knowledge”

A single component can expand to many units — one CloudFormation stack per instance in a cluster, one host in a fleet. The fan-out is authored in the composition, never known by the driver.

A fan-out unit is itself a small composition. One EC2 instance is provision (cfn-deploy) + code deploy (code-deploy) + health. A component that fans out over N instances composes N such mini-compositions, sequenced seed-first then rolling with a health gate between:

deploy: [
phase("Seed", [cfnDeploy({ stack: "neo4j-az0-0", template: "archive:neo4j.template.json" }), codeDeploy({ instance: 0, revision: "$env.appBundle" }), waitClusterHealthy({ size: 1 })]),
...followers.map((n) => // Array.map over instance configs
phase(`Node ${n}`, [cfnDeploy({ stack: `neo4j-${n}`, template: "archive:neo4j.template.json" }), codeDeploy({ instance: n, revision: "$env.appBundle" }), waitClusterHealthy({ quorum: true })]),
),
]
One component expanding into N per-instance mini-compositions — provision, code deploy, health — sequenced seed-first then rolling, with a health gate between each node. One component expanding into N per-instance mini-compositions — provision, code deploy, health — sequenced seed-first then rolling, with a health gate between each node.
Fan-out: one component composes N per-instance mini-compositions. Single-host is the N=1 case; a fleet is the same shape at N>1.

The driver never learns that a Neo4j cluster seeds first. If a composition ever needs an if component.name === … in the driver, the contract or a capability is missing expressiveness — fix it there, never in the driver.

For wiring one component’s data into another — cross-stack outputs and cross-component artifact references — see Wiring Components.

  • Wiring Components — cross-stack outputs and cross-component artifact outputs, the two ways components reference each other.
  • Build Archive — where a producer’s artifact lives before it is published.
  • Orchestration — how the graph order becomes a run.