Skip to main content

atmos stack create

Create a new stack using the existing scaffold catalog and generation engine. Preview the rendered files and generation hooks before writing. Existing files are never overwritten.

atmos stack create --help
 

Usage​

atmos stack create --file=stacks/deploy/dev.yaml --name=dev
atmos stack create --file=stacks/deploy/dev.yaml \
--import=catalog/defaults \
--component=terraform:network \
--component=helmfile:services \
--dry-run

Choose either --file for a manifest or --target for a directory layout. These flags are mutually exclusive. A --file must end in .yaml or .yml and match the project's stack discovery paths. A relative --file resolves from the project base path, not the current directory, and output files are rooted there too. Relative source paths in scaffold.templates resolve from the configuration file that declares the source. Named templates honor --config, configuration imports, and active profiles. --name explicitly sets the stack name in the built-in scaffold. When omitted, the generated manifest leaves naming to the project's conventions; provide the variables required by your stacks.name_template, directly or through imports.

Repeat --import to add imports and --component=kind:name to add component stubs. These stubs have metadata.enabled: false and empty vars. Configure them and enable them when ready. The command does not generate component sources unless your selected scaffold includes them. Component order does not imply dependencies.

If a write fails or creation is canceled, Atmos rolls back files created by that attempt so you can correct the cause and retry. It preserves preexisting files, hook-created files, and generated files changed after creation. If cleanup cannot finish, the error lists the remaining paths for manual recovery. A replaced stale generation record is restored when possible. Hook side effects are not rolled back. If generation succeeds but an after hook fails, the generated files and record remain.

Flags​

--file
Path of the new stack manifest. Mutually exclusive with --target. Must end in .yaml or .yml and fall under the project's stack discovery paths. Existing files are never overwritten.
--target
Directory for generated stack files. Mutually exclusive with --file. Relative paths resolve from the project base path. The directory must be under stacks.base_path; template outputs are relative to it. Existing directories are allowed, but existing files are never overwritten.
--template
Scaffold name or source: a name from scaffold.templates, an embedded catalog template, or a direct local or remote source. Default: stack.
--name
Explicit stack name. When omitted, the generated manifest follows the project's naming convention. Default: Empty.
--import
Stack import to add. Repeatable. Each occurrence is one value, so commas and braces such as catalog/{a,b} are kept as written. Default: None.
--component
Disabled component stub to add, in the form kind:name. Repeatable. The kind must be a supported component kind, including custom kinds declared by custom commands, and the name cannot contain whitespace. Duplicates are rejected. Default: None.
--set
Scaffold answer in the form key=value. Repeatable. An entry without = is an error. The reserved inputs stack_file, stack_name, stack_imports, and stack_components cannot be set. Default: None.
--ref
Git revision to use for a scaffold fetched from a Git source. Using it with an embedded or local scaffold is an error. Default: The source's default revision.
--interactive, -i
Prompt for the destination and scaffold answers when connected to a terminal, including during --dry-run. Without a terminal, Atmos uses defaults and errors on missing required inputs. Default: true.
--defaults
Use scaffold defaults and --set values without prompting. --interactive=false has the same effect. Default: false.
--skip-hooks[=names]
Skip all scaffold hooks, or the comma-separated hook names. Environment variable: ATMOS_SKIP_HOOKS. Default: No hooks skipped.
--dry-run
Print the files and scaffold hooks without writing or running anything. Environment variable: ATMOS_DRY_RUN. Default: false.

The template must consume the flags you pass. If --name, --import, or --component is given and the rendered manifest does not contain the value (or no generated stack document contains it in directory mode), creation fails and names the flag, so no input is dropped silently. A custom template reads these flags through stack_name, stack_imports, and stack_components.

Checks before writing​

Before any hook runs or any file is written, Atmos processes the existing stack manifests together with every generated stack file, using the same pipeline as atmos describe stacks. Creation fails, and nothing is written, when the result has:

  • A stack name that cannot be resolved. Pass --name, or set the variables that stacks.name_template uses.
  • A missing import. Import paths are relative to stacks.base_path; create the imported manifest or correct the --import value.
  • A component defined in more than one top-level manifest resolving to the same stack. Disjoint component definitions may share a stack name. Choose distinct component definitions or stack names, or edit the existing stack with atmos stack config set.
  • An invalid generated stack file.

If the project's existing stacks already fail to process, the error says so and points to atmos validate stacks, rather than blaming the new files.

Existing files are never overwritten. When the manifest exists, edit it with atmos stack config set or delete it first and run the command again.

Use an existing scaffold​

--template selects a name from the existing scaffold.templates configuration, an embedded/catalog template, or a direct local or remote source. Without it, creation uses the built-in stack scaffold.

atmos.yaml
scaffold:
templates:
application-stack:
description: Application stack with network and services
source: ./scaffolds/application-stack
atmos stack create --template application-stack \
--file stacks/deploy/dev.yaml --set environment=dev --dry-run

For --file, a stack-compatible scaffold declares its manifest output using spec.stack.manifest:

scaffolds/application-stack/scaffold.yaml
apiVersion: atmos/v1
kind: AtmosScaffoldConfig
metadata:
name: application-stack
spec:
stack:
manifest: '{{ .Config.stack_file }}'
fields:
- name: environment
type: input
required: true
files:
- path: stack.yaml
target: '{{ .Config.stack_file }}'
scaffolds/application-stack/stack.yaml
# atmos:template
vars:
stage: {{ .Config.environment | quote }}
components:
terraform:
network:
vars: {}

The generated manifest must match --file. Other outputs are relative to the project base path; a scaffold can conditionally create component sources or documentation. Custom templates decide how to use these reserved inputs:

stack_file
Project-relative manifest path from --file. In directory mode, defaults to stack.yaml, relative to --target; templates do not have to use it.
stack_name
Explicit --name, or an empty string.
stack_imports
List of requested imports.
stack_components
Component map containing disabled stubs, grouped by kind.

These inputs cannot be supplied through --set or declared as questionnaire fields. Existing template defaults, questions, conditions, matrices, and per-file delimiters work through the same engine as scaffold generate. Use --set key=value for answers, --defaults or --interactive=false for automation, and --ref to select a Git source revision. Required answers are validated before writing.

Create a directory layout​

Use --target when the recipe produces several stack files. It supports both one logical stack split across files and several distinct stacks:

atmos stack create --template application-stack \
--target stacks/deploy/dev \
--set environment=dev --set name=dev \
--component terraform:network --component helmfile:services \
--import catalog/defaults --dry-run

The template chooses which files receive the requested imports and component stubs. Each supplied value must appear in a generated stack document. The --set name=dev answer belongs to the template; --name dev supplies the reserved stack_name input.

Directory templates do not need spec.stack.manifest. If they declare it, its path is relative to the target and must identify a generated, discoverable stack manifest. The built-in stack template creates stack.yaml inside the target directory.

For example, a recipe can generate this layout:

stacks/deploy/dev/
├── _defaults.yaml
├── network.yaml
└── services.yaml

Configure discovery to include deploy/**/* and exclude **/_*. The excluded _defaults.yaml is an import fragment, while the other two files are entrypoints:

scaffold.yaml
apiVersion: atmos/v1
kind: AtmosScaffoldConfig
metadata:
name: application-stack
spec:
fields:
- name: environment
type: input
required: true
- name: name
type: input
required: true
files:
- path: _defaults.yaml
- path: network.yaml
- path: services.yaml
_defaults.yaml
# atmos:template
name: {{ .Config.name | quote }}
vars:
environment: {{ .Config.environment | quote }}
network.yaml
# atmos:template
import:
- ./_defaults
{{ range .Config.stack_imports }} - {{ . | quote }}
{{ end }}components:
terraform:
{{ range $name, $_ := .Config.stack_components.terraform }} {{ $name | quote }}:
metadata:
enabled: false
vars: {}
{{ end }}

The services.yaml template follows the same pattern using the helmfile group from stack_components. Both entrypoints import the shared name and variables; their distinct components participate in one logical stack. To create separate stacks, give their entrypoints distinct names or naming variables. Existing scaffold matrices can repeat an entrypoint for several environments or regions.

Files do not merge merely because they share a directory. Atmos uses its existing imports, discovery, and stack naming rules. At least one generated stack file must match discovery; excluded fragments can be imported by entrypoints. All generated stack YAML is validated before hooks or writes. Output paths cannot escape the target.

Interactive inputs​

When no destination is supplied in an interactive terminal, Atmos asks for a single file or directory layout, then its destination. The single-file option is selected initially. The scaffold questionnaire follows, with defaults and --set answers prefilled for review. Required fields, conditions, and dynamic choices behave like scaffold generate.

Interactive dry runs collect answers and then preview the files. Pass --defaults or --interactive=false to suppress prompts. Without a terminal, provide a destination and any required answers that have no defaults. Canceling a prompt writes nothing and runs no hooks.

Preview, hooks, and generation records​

A dry run prints a stream of file previews: a # <path> comment followed by each file's content, with --- between files. The stream goes to stdout so it can be piped, but it is not guaranteed to be valid YAML: files can contain Terraform sources, documentation, or other content. It creates no output files or directories and runs no hooks. Resolving a remote template can still download it.

The preview also lists each scaffold hook in the order it would run, with before hooks ahead of after hooks, including its actions and conditions. A hook whose events are not scaffold events is listed as ignored, along with the events it declares, and a hook skipped by --skip-hooks is identified as skipped.

Scaffold hooks run around file creation using the normal before.scaffold.generate and after.scaffold.generate events. Use --skip-hooks to skip all, or --skip-hooks=name1,name2 for specific hooks. These are separate from component hooks that run during deployment. Step-backed scaffold hooks receive the outcome of the creation as ATMOS_HOOK_STATUS (success or failure), ATMOS_HOOK_EXIT_CODE, and ATMOS_HOOK_ERROR. Hooks on before events always run with a success status.

Every destination is checked before hooks or writes. Files are created exclusively, so existing stack manifests, component sources, and project files are never overwritten. Creation writes the same rendered content shown in the preview. Filesystem or hook failures are reported; external hook effects are not rolled back automatically.

Each creation has an independent generation record under .atmos/stack-generations/. File-mode records are keyed by the project-relative manifest path. Directory-mode records use a separate key for the target directory and list its generated manifests. Each record stores the template, answers, source revision when available, and generated file hashes. Directory hooks use the target directory as their default working directory. Creating another stack does not replace project-level init/scaffold records. If you delete a created manifest and run stack create for the same path again, the new run replaces that manifest's generation record. A directory record can be replaced only after all outputs recorded by the previous generation have been removed. Updating an existing stack from this record is not yet supported by stack create.

init bootstraps a project; scaffold generate runs general recipes; stack create requires and validates a stack output. Creation changes configuration only. Use stack config to edit values and stack deploy to deploy components.