Skip to main content

Configure Dependencies Between Components

Atmos supports configuring the relationships between components in the same or different stacks. You can define dependencies between components to ensure that components are deployed in the correct order.

Before deploying components, it's important to consider the dependencies between components. For example, a database component might depend on a network component. When this happens, it's important to ensure that the network component is deployed before the database component.

Support for Dependencies

Support for dependencies is reliant on the integration used and not all integrations support dependencies.

For example, GitHub Actions do not support dependency order applies, while Spacelift does.

You can define component dependencies by using the settings.depends_on section. The section used to define all the Atmos components (in the same or different stacks) that the current component depends on.

The settings.depends_on section is a map of objects. The map keys are just the descriptions of dependencies and can be strings or numbers. Provide meaningful descriptions or numbering so that people can understand what the dependencies are about.

Why is settings.depends_on a map instead of a list?

We originally implemented settings.depends_on as a list. However, since it’s not clear how lists should be deep-merged, so we decided to convert it to a map instead. In this map, the keys are lexicographically ordered, and based on that order, the dependencies are managed.

Each object in the settings.depends_on section has the following schema:

file (optional)
A file on the local filesystem that the current component depends on
folder (optional)
A folder on the local filesystem that the current component depends on
component (required if file or folder is not specified)
an Atmos component that the current component depends on
stack (optional)
The Atmos stack where the component is provisioned
namespace (optional)
The namespace where the component is provisioned
tenant (optional)
The tenant where the component is provisioned
environment (optional)
The environment where the component is provisioned
stage (optional)
The stage where the component is provisioned

One of component, file or folder is required.

If component is specified, you can provide the other context variables to define an Atmos stack other than the current stack.

For example, you can specify:

  • stack if the component is from a different Atmos stack
  • namespace if the component is from a different Organization
  • tenant if the component is from a different Organizational Unit
  • environment if the component is from a different region
  • stage if the component is from a different account
  • tenant, environment and stage if the component is from a different Atmos stack (e.g. tenant1-ue2-dev)
info

If stack is specified, it's processed first and the namespace, tenant, environment and stage attributes are ignored.

tip

You can use Atmos Stack Manifest Templating in depends_on. Atmos processes the templates first, and then detects all the dependencies, allowing you to provide the parameters to depends_on dynamically.

Examples

In the following example, we specify that the component1 component depends on the following:

  • The component2 component in the same Atmos stack as component1
  • The component3 component from the prod stage
  • The component4 component from the tenant1 tenant, ue2 environment and staging stage (tenant1-ue2-staging Atmos stack)
  • The component5 component from the tenant1-ue2-prod Atmos stack
  • The component6 component from the same Atmos stack as component1
  • The component7 component from the same tenant and stage as component1, but uw2 environment

tenant1-ue1-dev.yaml

vars:
tenant: "tenant1"
environment: "ue1"
stage: "dev"

components:
terraform:
component1:
settings:
depends_on:
1:
# If the context (`stack`, `namespace`, `tenant`, `environment`, `stage`) is not
# provided, the `component` is from the same Atmos stack as `component1`
component: "component2"
2:
# `component1` (in any stage) depends on `component3`
# from the `prod` stage (in any `environment` and any `tenant`)
component: "component3"
stage: "prod"
3:
# `component1` depends on `component4`
# from the the `tenant1` tenant, `ue2` environment and `staging` stage
# (`tenant1-ue2-staging` Atmos stack)
component: "component4"
tenant: "tenant1"
environment: "ue2"
stage: "staging"
4:
# `component1` depends on `component5`
# from the `tenant1-ue2-prod` Atmos stack
component: "component5"
stack: "tenant1-ue2-prod"
5:
# `component1` depends on `component6`
# from the same Atmos stack
component: "component6"
stack: "{{ .vars.tenant }}-{{ .vars.environment }}-{{ .vars.stage }}"
6:
# `component1` depends on `component7`
# from the same tenant and stage as `component1`, but `uw2` environment
component: "component7"
stack: "{{ .vars.tenant }}-uw2-{{ .vars.stage }}"
vars:
enabled: true

Specifying stack

The stack attribute has higher precedence than the other context variables. If stack is specified, the namespace, tenant, environment and stage attributes are ignored.

As you can see in the examples above, we can use Atmos Stack Manifest Templating in the stack attribute to dynamically specify the stack.

This is useful when configuring stacks.name_template in atmos.yaml to define and refer to stacks. In this case, you can't use the context variables namespace, tenant, environment and stage in depends_on.

For example, in atmos.yaml, we specify stacks.name_template to define Atmos stacks, and enable templating:

atmos.yaml

stacks:
base_path: "stacks"
name_template: "{{ .settings.context.tenant }}-{{ .settings.context.environment }}-{{ .settings.context.stage }}"

# `Go` templates in Atmos manifests
templates:
settings:
enabled: true
note

In this example, stacks are defined by the settings.context section, not vars.

In the tenant1-uw2-dev Atmos stack, we can use the following depends_on configuration to define the component dependencies:

tenant1-uw2-dev.yaml

settings:
context:
tenant: "tenant1"
environment: "uw2"
stage: "dev"

components:
terraform:
vpc:
vars:
enabled: true

tgw/attachment:
settings:
depends_on:
1:
# `tgw/attachment` depends on the `vpc` component
# from the same Atmos stack (same tenant, account and region)
component: vpc
# NOTE: The same stack can be specified by using exactly the same template as in
# `stacks.name_template` in `atmos.yaml`, but it's not required and not recommended.
# If the dependent component is from the same stack, just omit the `stack` attribute completely.
# stack: "{{ .settings.context.tenant }}-{{ .settings.context.environment }}-{{ .settings.context.stage }}"
2:
# `tgw/attachment` depends on the `tgw/hub` components
# from the same tenant and account, but in `us-east-1` region (`ue1` environment)
component: tgw/hub
stack: "{{ .settings.context.tenant }}-ue1-{{ .settings.context.stage }}"

tgw/cross-region-hub-connector:
settings:
depends_on:
1:
# `tgw/cross-region-hub-connector` depends on `tgw/hub` components
# in the same tenant and account, but in `us-east-1` region (`ue1` environment)
component: tgw/hub
stack: "{{ .settings.context.tenant }}-ue1-{{ .settings.context.stage }}"

Execute the following Atmos commands to see the component dependencies:

atmos describe dependents vpc -s tenant1-uw2-dev --pager off

> atmos describe dependents vpc -s tenant1-uw2-dev --pager off
[
{
"component": "tgw/attachment",
"component_type": "terraform",
"stack": "tenant1-uw2-dev",
"stack_slug": "tenant1-uw2-dev-tgw-attachment"
}
]

atmos describe dependents tgw/hub -s tenant1-ue1-dev --pager off

> atmos describe dependents tgw/hub -s tenant1-ue1-dev --pager off
[
{
"component": "tgw/attachment",
"component_type": "terraform",
"stack": "tenant1-uw2-dev",
"stack_slug": "tenant1-uw2-dev-tgw-attachment"
},
{
"component": "tgw/cross-region-hub-connector",
"component_type": "terraform",
"stack": "tenant1-uw2-dev",
"stack_slug": "tenant1-uw2-dev-tgw-cross-region-hub-connector"
}
]
tip

For more information, refer to atmos describe dependents and atmos describe affected CLI commands.