Mappings Support¶
You can provide a mappings YAML file to inject key-value maps into your templates. This is useful for referencing environment-specific values, IDs, or any other mapping you want to use in your generated files.
What are Mappings?¶
Mappings are external data files that provide structured key-value pairs for use in your STRUCT templates. They allow you to:
- Separate data from templates
- Share common values across multiple structures
- Manage environment-specific configurations
- Centralize reference data like account IDs, team names, or service endpoints
Mappings File Format¶
Basic Structure¶
mappings:
teams:
devops: devops-team
frontend: frontend-team
backend: backend-team
aws_account_ids:
development: 123456789012
staging: 234567890123
production: 345678901234
service_endpoints:
api_gateway: https://api.example.com
database: postgres://db.example.com:5432
redis: redis://cache.example.com:6379
Nested Mappings¶
mappings:
environments:
development:
database_url: postgres://dev-db:5432/myapp
redis_url: redis://dev-cache:6379
debug: true
production:
database_url: postgres://prod-db:5432/myapp
redis_url: redis://prod-cache:6379
debug: false
regions:
us_east_1:
vpc_id: vpc-12345
subnet_ids:
- subnet-abc123
- subnet-def456
eu_west_1:
vpc_id: vpc-67890
subnet_ids:
- subnet-ghi789
- subnet-jkl012
Using Mappings in Templates¶
Basic Usage¶
Reference mapping values using the mappings
variable:
files:
- config.yml:
content: |
database_url: {{@ mappings.service_endpoints.database @}}
api_endpoint: {{@ mappings.service_endpoints.api_gateway @}}
# Team information
owner: {{@ mappings.teams.backend @}}
Array Access¶
For nested structures and arrays:
files:
- terraform/main.tf:
content: |
resource "aws_instance" "web" {
ami = "ami-12345"
instance_type = "t3.micro"
vpc_security_group_ids = [
"{{@ mappings.regions.us_east_1.vpc_id @}}"
]
subnet_id = "{{@ mappings.regions.us_east_1.subnet_ids[0] @}}"
}
Dynamic Key Access¶
Use bracket notation for dynamic keys:
files:
- app.py:
content: |
import os
ENVIRONMENT = "{{@ environment @}}"
DATABASE_URL = "{{@ mappings.environments[environment].database_url @}}"
DEBUG = {{@ mappings.environments[environment].debug @}}
variables:
- environment:
description: "Target environment"
type: string
default: "development"
Using Mappings in the with
Clause¶
You can assign values from mappings directly in the with
clause for folder struct calls:
folders:
- ./infrastructure:
struct: terraform/aws-vpc
with:
vpc_id: {{@ mappings.regions.us_east_1.vpc_id @}}
subnet_ids: {{@ mappings.regions.us_east_1.subnet_ids @}}
- ./backend:
struct: project/django
with:
team: {{@ mappings.teams.backend @}}
database_url: {{@ mappings.environments.production.database_url @}}
This approach allows you to pass specific mapping values as variables to nested structures.
Command Line Usage¶
Use the --mappings-file
argument with the generate
command:
# Both commands work identically - file:// is automatically added for .yaml files
struct generate --mappings-file ./mymap.yaml my-struct.yaml .
struct generate --mappings-file ./mymap.yaml file://my-struct.yaml .
Multiple Mappings Files¶
You can specify multiple mappings files that will be merged in order:
struct generate \
--mappings-file ./common-mappings.yaml \
--mappings-file ./env-specific-mappings.yaml \
my-struct.yaml .
Merging behavior:
- Files are processed in the order specified
- Later files override earlier ones for conflicting keys
- Deep merging is performed for nested dictionaries
- This enables clean separation of common vs environment-specific configuration
Example with environment variable:
struct generate \
--mappings-file ./mappings/common.yaml \
--mappings-file ./mappings/${ENVIRONMENT}.yaml \
infrastructure.yaml \
./output
Practical Examples¶
Multi-Environment Deployment¶
mappings.yaml:
mappings:
environments:
dev:
namespace: myapp-dev
replicas: 1
image_tag: latest
resources:
cpu: 100m
memory: 128Mi
prod:
namespace: myapp-prod
replicas: 3
image_tag: v1.2.3
resources:
cpu: 500m
memory: 512Mi
k8s-deployment.yaml template:
files:
- k8s/deployment.yaml:
content: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{@ app_name @}}
namespace: {{@ mappings.environments[target_env].namespace @}}
spec:
replicas: {{@ mappings.environments[target_env].replicas @}}
template:
spec:
containers:
- name: app
image: myapp:{{@ mappings.environments[target_env].image_tag @}}
resources:
requests:
cpu: {{@ mappings.environments[target_env].resources.cpu @}}
memory: {{@ mappings.environments[target_env].resources.memory @}}
variables:
- target_env:
description: "Target environment (dev/prod)"
type: string
default: "dev"
- app_name:
description: "Application name"
type: string
Team-Specific Configurations¶
teams.yaml:
mappings:
teams:
platform:
email: platform@company.com
slack: "#platform-team"
oncall: platform-oncall@company.com
data:
email: data@company.com
slack: "#data-team"
oncall: data-oncall@company.com
Usage:
folders:
- ./services/api:
struct: service/rest-api
with:
team_email: {{@ mappings.teams.platform.email @}}
team_slack: {{@ mappings.teams.platform.slack @}}
- ./services/etl:
struct: service/data-pipeline
with:
team_email: {{@ mappings.teams.data.email @}}
team_slack: {{@ mappings.teams.data.slack @}}
Best Practices¶
-
Organize by Context: Group related mappings together (e.g., environments, teams, regions)
-
Use Consistent Naming: Follow naming conventions across all mapping files
-
Version Control: Keep mappings files in version control alongside your structures
-
Validate Data: Ensure mapping values are correct before generating structures
-
Document Mappings: Include comments or separate documentation for complex mappings
-
Environment Separation: Use separate mapping files for different environments
-
Default Values: Provide sensible defaults in your templates for missing mappings
Error Handling¶
If a mapping key doesn't exist, STRUCT will show an error:
files:
- config.yml:
content: |
# This will cause an error if 'nonexistent' key doesn't exist
value: {{@ mappings.nonexistent.key @}}
Use the default
filter to provide fallbacks: