Skip to main content

Blueprint Configuration

Atmos Design Pattern

The Blueprint Configuration pattern creates reusable deployment templates that bundle multiple components with sensible defaults. Top-level stacks import a blueprint and customize only what differs per deployment.

What Is a Blueprint?

A blueprint is a stack manifest that bundles multiple components into a reusable deployment template. It sits above catalogs and archetypes in the abstraction hierarchy:

  • A catalog defines defaults for a single component (e.g., catalog/vpc/defaults.yaml)
  • An archetype is a pre-configured variant of a single component for a specific use case (e.g., catalog/s3-bucket/logging.yaml), typically using metadata.inherits
  • A blueprint composes multiple components together into a complete deployment type (e.g., networking + compute + storage for a multi-tenant platform)

Catalogs and archetypes answer "how should this component be configured?" Blueprints answer "what components make up this type of deployment, and what are the sensible defaults?"

Use-cases

Use the Blueprint Configuration pattern when:

  • You manage many deployments of the same architecture (e.g., multi-tenant, multi-region)

  • Each deployment follows a common pattern but needs deployment-specific values (CIDRs, instance sizes, etc.)

  • You want to prevent drift between deployments by sharing a single source of truth

  • Different deployment types have different component compositions (e.g., multi-tenant vs single-tenant)

Benefits

  • One blueprint per deployment type — changes propagate to all deployments automatically

  • Top-level stacks are minimal — just an import and deployment-specific values

  • Composable — blueprints import layers, layers import component defaults

  • No overrides needed — plain vars at the same scope level handles customization

Example

The following is one opinionated implementation using dedicated layers/ and blueprints/ directories. Your project may organize these differently — what matters is the pattern of composing component catalogs into a reusable template that deployment stacks import.

Directory Structure

   ├── stacks
│ ├── catalog # Component defaults
│ │ ├── vpc
│ │ │ └── defaults.yaml
│ │ ├── eks
│ │ │ └── defaults.yaml
│ │ └── rds
│ │ └── defaults.yaml
│ ├── layers # Infrastructure layers
│ │ ├── networking.yaml
│ │ ├── compute.yaml
│ │ └── storage.yaml
│ ├── blueprints # Deployment type templates
│ │ ├── multi-tenant.yaml
│ │ └── single-tenant.yaml
│ └── deploy # One file per deployment
│ ├── mt-prod-us.yaml
│ ├── mt-prod-eu.yaml
│ └── st-prod-us-customer1.yaml

└── components
└── terraform
├── vpc
├── eks
└── rds

Component Defaults (Catalog)

Component defaults define the baseline configuration for each Terraform component:

stacks/catalog/vpc/defaults.yaml

components:
terraform:
vpc:
metadata:
component: vpc
vars:
enable_dns_hostnames: true
enable_dns_support: true
enable_nat_gateway: true

stacks/catalog/rds/defaults.yaml

components:
terraform:
rds:
metadata:
component: rds
vars:
engine: postgres
engine_version: "15"
backup_retention_period: 7

Layers

Layers group related component defaults by infrastructure function:

stacks/layers/networking.yaml

import:
- catalog/vpc/defaults

stacks/layers/storage.yaml

import:
- catalog/rds/defaults

Blueprints

Blueprints import layers and define configurable defaults. The key is to define defaults at the global vars level so that deployment stacks can easily override them:

stacks/blueprints/multi-tenant.yaml

import:
- layers/networking
- layers/compute
- layers/storage

# Configurable defaults at the global level
vars:
tenant_model: multi-tenant
cidr_block: "10.0.0.0/16"
rds_instance_type: "db.r5.large"
eks_node_instance_type: "t3.large"
eks_node_count: 3

stacks/blueprints/single-tenant.yaml

import:
- layers/networking
- layers/compute
- layers/storage

# Single-tenant gets a smaller footprint by default
vars:
tenant_model: single-tenant
cidr_block: "10.0.0.0/24"
rds_instance_type: "db.t3.medium"
eks_node_instance_type: "t3.medium"
eks_node_count: 2

Deployment Stacks

Each deployment imports its blueprint and overrides only what's specific to that deployment:

stacks/deploy/mt-prod-us.yaml

import:
- blueprints/multi-tenant

# Deployment-specific values override blueprint defaults
vars:
stage: prod
region: us-east-1
cidr_block: "172.16.0.0/16"
rds_instance_type: "db.r5.12xlarge"

stacks/deploy/mt-prod-eu.yaml

import:
- blueprints/multi-tenant

vars:
stage: prod
region: eu-west-1
cidr_block: "172.17.0.0/16"
# Uses blueprint default for rds_instance_type

stacks/deploy/st-prod-us-customer1.yaml

import:
- blueprints/single-tenant

vars:
stage: prod
region: us-east-1
tenant: customer1
cidr_block: "10.100.0.0/24"

This works because both the blueprint and the deployment stack define vars at the same scope level (global). The importing file's values override the imported file's values.

Why You Don't Need overrides

The overrides section exists for a different problem: file-scoped variable application. When multiple manifests (e.g., team A and team B) are imported into the same top-level stack, overrides prevents one team's settings from leaking into the other team's components.

In the blueprint pattern, each deployment stack imports a single blueprint. There's no competing manifest to leak into, so overrides adds no value. Plain vars at the same scope level is all you need.

The Scope Trap

If your blueprint defines defaults at the component level instead of the global level, you must override at the component level too.

Blueprint with component-level defaults

# If the blueprint puts cidr_block HERE (component level)...
components:
terraform:
vpc:
vars:
cidr_block: "10.0.0.0/16"

Deployment stack (wrong way)

import:
- blueprints/multi-tenant

# ...setting it HERE (global level) won't override it
vars:
cidr_block: "172.16.0.0/16" # This loses! Component level beats global level.

Deployment stack (right way)

import:
- blueprints/multi-tenant

# Override at the SAME level
components:
terraform:
vpc:
vars:
cidr_block: "172.16.0.0/16" # This wins

References