Skip to content

Multi-Stack Output

An estate past one stack splits into side-by-side projects — each stack its own project, its own flat src/, its own build. This page covers what that means at the serialization layer. For the project-level view, see Multi-Stack Projects.

One invocation, one output path. Within that invocation, chant partitions entities by lexicon — a project declaring aws and k8s yields one serialized document per lexicon, since each lexicon serializes to its own deployable artifact (a CloudFormation template, a Kubernetes manifest, a CI config).

Directory structure is not a partitioning input. chant build src on a project whose src/ holds subdirectories produces one build of everything under src/, not one output per subdirectory.

So a side-by-side project builds exactly the way a single-stack project does, because that is what it is:

Terminal window
chant build src -o dist/template.json

There is no multi-stack build mode. Several stacks means several projects, each running that.

References cross by name, declared on both sides.

The producer marks a value for export. When the serializer encounters a StackOutput entity it emits it into the template’s outputs section:

export const clusterArn = output(shared.cluster.Arn, "ClusterArn");

The consumer declares a parameter that the value is fed into at deploy time — --parameter-overrides for CloudFormation, each lexicon’s own mechanism elsewhere:

export const clusterArn = new Parameter("String", { description: "ECS Cluster ARN" });

Nothing is resolved at build time and nothing is shared between the two builds. Each template is complete and independently valid; the handle names are the contract.

Both halves are surfaced so a consumer can reconstruct the link without parsing templates:

  • exports — the output name (the handle another stack imports by), the node producing it, and the producer-side attribute it reads.
  • imports — the parameter name and its node.

Match an import’s name against another stack’s export name to draw the cross-stack edge. In-stack, the parameter’s own consumers are ordinary $ref edges.

Composition across projects belongs to the viewer, not to chant: chant graphs one project and emits the handles, and a tool pointed at several joins them.

groups.byStack maps stack name to node ids — what a renderer reads to draw boundary boxes.

For a project that declares stacks in chant.config.ts, chant graph builds each stack’s source in isolation, qualifies node ids <stack>::<id> to match how observation keys live nodes, and groups by the declared names.

For a project built from one source tree — including every side-by-side project — groups.byStack reports the lexicon partition, which is the unit that tree deploys as.

Child projects (lexicon-specific nested stacks)

Section titled “Child projects (lexicon-specific nested stacks)”

Some lexicons support child projects — subdirectories that build to separate output files, referenced from a parent that deploys them as a unit. Unlike side-by-side projects, these are declared in code.

chant’s core provides two primitives:

  • stackOutput(ref) — marks a value for cross-stack export. When the serializer encounters a StackOutput entity, it emits it into the template’s Outputs section.
  • ChildProjectInstance — a Declarable representing a reference to a child project directory. The build pipeline detects these, recursively builds the child, and attaches the child’s BuildResult for the serializer.

Discovery stops at child project boundaries — findInfraFiles() does not recurse into child project subdirectories. Each child project is a separate project scope, only built when referenced by a ChildProjectInstance.

When a serializer produces multiple files, it returns a SerializerResult with a primary template plus additional files:

interface SerializerResult {
/** Primary template content */
primary: string;
/** Additional files keyed by filename */
files?: Record<string, string>;
}

The build pipeline writes additional files alongside the primary output. For example, the AWS lexicon’s nestedStack() produces child CloudFormation templates with explicit cross-stack reference wiring via stackOutput(). See the AWS Nested Stacks guide.

For lexicon authors implementing child project support, see Child Projects.