Multi-Stack Output
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.
What chant build partitions on
Section titled “What chant build partitions on”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:
chant build src -o dist/template.jsonThere is no multi-stack build mode. Several stacks means several projects, each running that.
Cross-stack references
Section titled “Cross-stack references”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.
What the IR carries
Section titled “What the IR carries”The IR carries both halves, so a consumer can rebuild the link without parsing templates:
exports— the outputname(the handle another stack imports by), the node producing it, and the producer-side attribute it reads.imports— the parameternameand 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.
Stack grouping in the IR
Section titled “Stack grouping in the IR”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 aStackOutputentity, it emits it into the template’sOutputssection.ChildProjectInstance— aDeclarablerepresenting a reference to a child project directory. The build pipeline detects these, recursively builds the child, and attaches the child’sBuildResultfor 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.