Import Stack Configurations
Imports let you split stack configurations across multiple files and reuse them. Each import is deep-merged on top of previous imports, building up the final configuration.
Use Cases
- DRY Configuration: Reduce duplication by sharing common settings across stacks.
- Blueprints: Define reusable baselines that any stack can import as a starting point.
- Service Catalogs: Provide golden-path configurations that teams can compose into architectures.
Overusing imports can make configurations harder to understand. We recommend limiting import depth to maintain clarity. Review our best practices for practical guidance.
Configuration
Define an import section at the top of any stack configuration:
import:
- catalog/file1 # First import "file1" from the catalog
- catalog/file2 # Second import "file2" from the catalog, deep merging on top of the first import
- catalog/file3 # Third import "file3" from the catalog, deep merging on top of the preceding imports
The base path for imports is specified in the atmos.yaml in the stacks.base_path section.
If no file extension is used, Atmos appends .yaml automatically.
Automatic Template File Detection
When importing files without an extension, Atmos searches for template versions automatically. The search order is:
.yaml.yml.yaml.tmpl.yml.tmpl
If both a .yaml and a .yaml.tmpl version exist, Atmos uses the template version. Template files are skipped during atmos validate stacks since they contain placeholders that are invalid YAML before rendering.
Import Path Resolution
Atmos supports two types of import paths:
Base-Relative Paths (Default)
Most imports use paths relative to the stacks.base_path configured in atmos.yaml:
catalog/vpc/defaultsmixins/region/us-east-2orgs/acme/_defaults
These paths are resolved from the base stacks directory, regardless of where the importing file is located.
File-Relative Paths
Imports starting with . or .. are relative to the current file's directory:
./_defaults- imports from the same directory as the current file../shared/_defaults- imports from a siblingshareddirectory
This is useful when you want to import files that are co-located with the current configuration.
Remote Imports
Atmos supports importing stack configurations from remote sources using go-getter URL schemes. This enables sharing configurations across repositories, teams, or organizations.
Supported Schemes
git::- Git Repositories- Import from Git repositories over HTTPS or SSH.
github.com/- GitHub Shorthand- Shorthand syntax for GitHub repositories.
s3::- Amazon S3- Import from S3 buckets using AWS credentials.
gcs::- Google Cloud Storage- Import from GCS buckets using Google Cloud credentials.
https:///http://- HTTP(S)- Import from any HTTP(S) URL.
file://- Local Files- Import from absolute local file paths.
Git Repository Examples
Import from a Git repository:
import:
# HTTPS with specific ref (branch, tag, or commit)
- git::https://github.com/acme/infrastructure.git//stacks/catalog/vpc?ref=v1.2.0
# SSH authentication
- git::git@github.com:acme/infrastructure.git//stacks/catalog/eks?ref=main
# GitHub shorthand
- github.com/acme/infrastructure//stacks/catalog/rds?ref=v2.0.0
The // separates the repository URL from the path within the repository. The ?ref= parameter specifies the Git ref (branch, tag, or commit SHA).
S3 Examples
Import from Amazon S3:
import:
# Basic S3 import
- s3::https://s3.amazonaws.com/acme-configs/stacks/catalog/vpc.yaml
# With region specified
- s3::https://s3-us-west-2.amazonaws.com/acme-configs/stacks/catalog/eks.yaml
S3 imports use your AWS credentials from the environment or AWS config files.
HTTP(S) Examples
Import from any HTTP(S) URL:
import:
# Direct HTTPS import
- https://raw.githubusercontent.com/acme/configs/main/stacks/catalog/vpc.yaml
# From internal artifact server
- https://artifacts.internal.acme.com/stacks/v1.0.0/defaults.yaml
Best Practices for Remote Imports
-
Pin Versions: Always use
?ref=with a specific tag or commit SHA for Git imports to ensure reproducible builds. -
Cache Considerations: Remote imports are cached locally. Use
atmos vendor pullto refresh cached imports. -
Authentication: Configure appropriate credentials for private repositories or buckets via environment variables or credential files.
-
Fallback to Local: Consider vendoring critical remote imports locally using
atmos vendor pullfor offline access and faster builds.
For more details on go-getter URL formats, see the go-getter documentation.
Conventions
We recommend placing all baseline "imports" in the stacks/catalog folder, however, they can exist anywhere.
Use mixins for reusable snippets of configurations that alter the behavior of Stacks in some way.
The _defaults.yaml Pattern
Many Atmos projects use _defaults.yaml as a naming convention for default configurations at each level of the hierarchy. This is purely a convention—Atmos has no special handling for these files. They must be explicitly imported like any other file.
The underscore prefix ensures they:
- Sort to the top of directory listings (lexicographic sorting)
- Are visually distinct from actual stack configurations
- Are excluded from stack discovery (via
excluded_pathsconfiguration)
The _defaults.yaml pattern is a common convention, not an Atmos feature. These files are only excluded from stack discovery because they match the pattern in excluded_paths configuration. They must always be explicitly imported to take effect.
For a complete explanation of this pattern, see the _defaults.yaml Design Pattern documentation.
Imports Schema
The import section accepts a list of strings (simple paths) or a list of objects (when using templates or feature flags).
Imports without Templates
For a list of paths to the imported files, just provide a list of strings like this:
import:
- mixins/region/us-east-2
- orgs/cp/tenant1/test1/_defaults
- catalog/terraform/top-level-component1
- catalog/terraform/test-component
- catalog/terraform/vpc
- catalog/helmfile/echo-server
Imports with Templates
Sometimes you may want to import files that use Go templates. Templates can be used with or without providing a context - files with .yaml.tmpl or .yml.tmpl extensions are always processed as Go templates.
Files with the .yaml.tmpl or .yml.tmpl extension are always processed as Go templates, regardless of whether context is provided.
This allows you to use template functions that don't require context (like {{ now }}, {{ env "VAR" }}, {{ uuidv4 }}, etc.) even without providing context variables.
If you don't want a file to be processed as a template, use the .yaml or .yml extension instead.
The skip_templates_processing flag can be used to explicitly skip template processing for any imported file.
Templating must be enabled in atmos.yaml for Atmos to process the imported files as Go templates.
For example, here we import a file with a template and provide a context to passing two variables.
import:
- path: "catalog/something.yaml.tmpl" # Path to the imported file with the required .tmpl extension for Go templates
context:
foo: bar
baz: qux
skip_templates_processing: false
ignore_missing_template_values: false
skip_if_missing: false
- path: "catalog/something.yaml.tmpl"
context: {}
skip_templates_processing: false
ignore_missing_template_values: true
skip_if_missing: true
You can also use templates without providing any context variables. This is useful for including dynamic values that don't depend on context:
import:
# This template file uses functions that don't require context
- path: "catalog/metadata.yaml.tmpl"
# No context needed - the template can use functions like:
# {{ now | date "2006-01-02" }}
# {{ env "BUILD_NUMBER" }}
# {{ uuidv4 }}
# {{ randAlphaNum 10 }}
Example template file (catalog/metadata.yaml.tmpl) without context:
metadata:
generated_at: {{ now | date "2006-01-02T15:04:05Z07:00" }}
build_number: {{ env "BUILD_NUMBER" | default "local" }}
deployment_id: {{ uuidv4 }}
version: "1.0.0"
The import section supports the following fields:
path- (string) required- The path to the imported file
context- (map)- An optional freeform map of context variables that are applied as template variables to the imported file (if the imported file is a Go template)
skip_templates_processing- (boolean)- Skip template processing for the imported file. Can be used if the imported file uses
Gotemplates that should not be interpreted by atmos. For example, sometimes configurations for components may pass Go template strings not intended for atmos. ignore_missing_template_values- (boolean)- Process templates but skip any values missing from the
contextinstead of throwing an error. Useful when the imported file contains Go templates for external systems (e.g. Datadog) that Atmos should not evaluate. Unlikeskip_templates_processingwhich skips all template processing, this option still evaluates templates that have matching context values. To apply this globally to all imports without setting it on each one, use thetemplates.settings.ignore_missing_template_valuessetting inatmos.yaml. skip_if_missing- (boolean)- Skip the import without error if the file does not exist.
A combination of the two formats is also supported:
import:
- mixins/region/us-east-2
- orgs/cp/tenant1/test1/_defaults
- path: "<path_to_atmos_manifest1>"
- path: "<path_to_atmos_manifest2>"
context: {}
skip_templates_processing: false
ignore_missing_template_values: true
Templated Imports
Atmos supports Go templates and Sprig functions in imported files. This lets you parameterize a configuration and reuse it with different values via the import context.
For example, we can define the following configuration for EKS Atmos components in the catalog/terraform/eks_cluster.yaml.tmpl template file:
# Imports can also be parameterized using `Go` templates
import: []
components:
terraform:
"eks-{{ .flavor }}/cluster":
metadata:
component: "test/test-component"
vars:
enabled: "{{ .enabled }}"
name: "eks-{{ .flavor }}"
service_1_name: "{{ .service_1_name }}"
service_2_name: "{{ .service_2_name }}"
tags:
flavor: "{{ .flavor }}"
Since Go processes files ending in .yaml.tmpl text files with templates, we can parameterize the Atmos component name eks-{{ .flavor }}/cluster and any values in any sections (vars, locals, settings, env, backend, etc.), and even the import section in the imported file (if the file imports other configurations).
Then we can import the template into a top-level stack multiple times providing different context variables to each import:
import:
- path: "mixins/region/us-west-2"
- path: "orgs/cp/tenant1/test1/_defaults"
# This import with the provided context will dynamically generate
# a new Atmos component `eks-blue/cluster` in the current stack
- path: "catalog/terraform/eks_cluster.yaml.tmpl"
context:
flavor: "blue"
enabled: true
service_1_name: "blue-service-1"
service_2_name: "blue-service-2"
# This import with the provided context will dynamically generate
# a new Atmos component `eks-green/cluster` in the current stack
- path: "catalog/terraform/eks_cluster.yaml.tmpl"
context:
flavor: "green"
enabled: false
service_1_name: "green-service-1"
service_2_name: "green-service-2"
Now we can execute the following Atmos commands to describe and provision the dynamically generated EKS components into the stack:
atmos describe component eks-blue/cluster -s tenant1-uw2-test-1
atmos describe component eks-green/cluster -s tenant1-uw2-test-1
atmos terraform apply eks-blue/cluster -s tenant1-uw2-test-1
atmos terraform apply eks-green/cluster -s tenant1-uw2-test-1
All the parameterized variables get their values from the context:
vars:
enabled: true
environment: uw2
name: eks-blue
namespace: cp
region: us-west-2
service_1_name: blue-service-1
service_2_name: blue-service-2
stage: test-1
tags:
flavor: blue
tenant: tenant1
vars:
enabled: true
environment: uw2
name: eks-green
namespace: cp
region: us-west-2
service_1_name: green-service-1
service_2_name: green-service-2
stage: test-1
tags:
flavor: green
tenant: tenant1
Hierarchical Imports with Context
Atmos supports hierarchical imports with context. This will allow you to parameterize the entire chain of stack configurations and dynamically generate components in stacks.
For example, let's create the configuration stacks/catalog/terraform/eks_cluster_hierarchical.yaml.tmpl with the following content:
import:
# Use `region.yaml.tmpl` `Go` template and provide `context` for it.
# This can also be done by using `Go` templates in the import path itself.
# - path: "mixins/region/{{ .region }}"
- path: "mixins/region/region.yaml.tmpl"
# `Go` templates in `context`
context:
region: "{{ .region }}"
environment: "{{ .environment }}"
# `Go` templates in the import path
- path: "orgs/cp/{{ .tenant }}/{{ .stage }}/_defaults"
components:
terraform:
# Parameterize Atmos component name
"eks-{{ .flavor }}/cluster":
metadata:
component: "test/test-component"
vars:
# Parameterize variables
enabled: "{{ .enabled }}"
name: "eks-{{ .flavor }}"
service_1_name: "{{ .service_1_name }}"
service_2_name: "{{ .service_2_name }}"
tags:
flavor: "{{ .flavor }}"
Then we can import the template into a top-level stack multiple times providing different context variables to each import and to the imports for
the entire inheritance chain (which catalog/terraform/eks_cluster_hierarchical.yaml.tmpl imports itself):
import:
# This import with the provided hierarchical context will dynamically generate
# a new Atmos component `eks-blue/cluster` in the `tenant1-uw1-test1` stack
- path: "catalog/terraform/eks_cluster_hierarchical.yaml.tmpl"
context:
# Context variables for the EKS component
flavor: "blue"
enabled: true
service_1_name: "blue-service-1"
service_2_name: "blue-service-2"
# Context variables for the hierarchical imports
# `catalog/terraform/eks_cluster_hierarchical.yaml.tmpl` imports other parameterized configurations
tenant: "tenant1"
region: "us-west-1"
environment: "uw1"
stage: "test1"
# This import with the provided hierarchical context will dynamically generate
# a new Atmos component `eks-green/cluster` in the `tenant1-uw1-test1` stack
- path: "catalog/terraform/eks_cluster_hierarchical.yaml.tmpl"
context:
# Context variables for the EKS component
flavor: "green"
enabled: false
service_1_name: "green-service-1"
service_2_name: "green-service-2"
# Context variables for the hierarchical imports
# `catalog/terraform/eks_cluster_hierarchical.yaml.tmpl` imports other parameterized configurations
tenant: "tenant1"
region: "us-west-1"
environment: "uw1"
stage: "test1"
When processing hierarchical imports, Atmos:
- Processes imports in the order they are listed
- Passes the parent's
contextto each imported file - If a child file defines its own
context, merges it with the parent — child values win on conflicts - Repeats this recursively through the entire import chain
We are now able to dynamically generate the components eks-blue/cluster and eks-green/cluster in the stack tenant1-uw1-test1 and can
execute the following Atmos commands to provision the components into the stack:
atmos terraform apply eks-blue/cluster -s tenant1-uw1-test-1
atmos terraform apply eks-green/cluster -s tenant1-uw1-test-1
All the parameterized variables get their values from the hierarchical context settings:
vars:
enabled: true
environment: uw1
name: eks-blue
namespace: cp
region: us-west-1
service_1_name: blue-service-1
service_2_name: blue-service-2
stage: test-1
tags:
flavor: blue
tenant: tenant1
Templated imports are powerful but make configurations harder to read and debug. Prefer plain imports and inheritance when possible. Reserve templates for cases where the duplication would be excessive — such as generating many similar components from a single definition.
Conditional Variables in Templates
Use Sprig functions like hasKey to conditionally include variables based on the provided context:
components:
terraform:
eks/iam-role/{{ .app_name }}/{{ .service_environment }}:
metadata:
component: eks/iam-role
settings:
spacelift:
workspace_enabled: true
vars:
enabled: {{ .enabled }}
tags:
Service: {{ .app_name }}
service_account_name: {{ .app_name }}
service_account_namespace: {{ .service_account_namespace }}
{{ if hasKey . "iam_managed_policy_arns" }}
iam_managed_policy_arns:
{{ range $i, $iam_managed_policy_arn := .iam_managed_policy_arns }}
- '{{ $iam_managed_policy_arn }}'
{{ end }}
{{- end }}
{{ if hasKey . "iam_source_policy_documents" }}
iam_source_policy_documents:
{{ range $i, $iam_source_policy_document := .iam_source_policy_documents }}
- '{{ $iam_source_policy_document }}'
{{ end }}
{{- end }}
The iam_managed_policy_arns and iam_source_policy_documents variables will be included in the component configuration only if the
provided context object has the iam_managed_policy_arns and iam_source_policy_documents fields.
Summary
Imports with context let you parameterize entire configuration files and generate component variations from a single template — useful for patterns like EKS blue-green deployments.