Skip to content

Multi-Stack Output

llms.txt lists every page for an agent

When an estate needs more than one stack, each stack becomes a side-by-side project with its own flat src/ and its own build. This page covers how those builds serialize. For the project-level view, see Multi-Stack Projects.

Each invocation writes one output path. Within it, 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, and the value is passed to it at deploy time: --parameter-overrides for CloudFormation, the 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 valid on its own, and the handle names are the contract.

The IR carries both halves, so a consumer can rebuild 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.

chant graphs one project and emits the handles. A tool pointed at several projects joins them.

groups.byStack maps stack name to node ids, which 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, which includes every side-by-side project, groups.byStack reports the lexicon partition, 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.

Each child project is a separate project scope, only built when referenced by a ChildProjectInstance. Discovery stops at every child project, so findInfraFiles() and chant lint never read a child project’s files as the parent’s own. See One walk for every command.

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.

chant