Templates and Functions
Comet uses Go templates with additional functions to enable dynamic configuration. This powerful feature allows you to reference variables, use conditional logic, and access cross-stack state.
Template Syntax
Templates use the {{ }}
syntax:
const vpc = component('vpc', 'modules/vpc', {
name: 'vpc-{{ .stack }}', // Becomes 'vpc-dev', 'vpc-prod', etc.
region: '{{ .settings.region }}'
})
Built-in Variables
.stack
The current stack name:
backend('gcs', {
bucket: 'terraform-state',
prefix: '{{ .stack }}/{{ .component }}' // dev/vpc, prod/vpc, etc.
})
.component
The current component name:
const database = component('db', 'modules/cloudsql', {
instance_name: '{{ .stack }}-{{ .component }}' // dev-db, prod-db
})
.settings
Access stack settings:
stack('production', {
project_id: 'my-gcp-project',
region: 'us-central1',
db_tier: 'db-n1-standard-2'
})
const db = component('db', 'modules/cloudsql', {
project: '{{ .settings.project_id }}',
region: '{{ .settings.region }}',
tier: '{{ .settings.db_tier }}'
})
Template Functions
state
- Cross-Stack References
Reference outputs from other stacks:
const app = component('app', 'modules/application', {
vpc_id: '{{ (state "infrastructure" "vpc").id }}',
db_host: '{{ (state "data" "database").connection_name }}'
})
See the Cross-Stack References page for more details.
secrets
- Encrypted Secrets
Access SOPS-encrypted secrets:
const db = component('database', 'modules/cloudsql', {
password: '{{ secrets "sops://secrets.enc.yaml#/database/password" }}'
})
See the Secrets Management page for more details.
Conditional Logic
Use if
, else
, and end
for conditional values:
const instance = component('vm', 'modules/compute', {
// Different machine types per environment
machine_type: '{{ if eq .stack "production" }}n1-standard-4{{ else }}n1-standard-1{{ end }}',
// Enable features only in production
deletion_protection: '{{ if eq .stack "production" }}true{{ else }}false{{ end }}'
})
Comparison Operators
eq
- Equal tone
- Not equal tolt
- Less thanle
- Less than or equalgt
- Greater thange
- Greater than or equal
const backup = component('backup', 'modules/backup', {
// Retention days based on environment
retention_days: '{{ if eq .stack "production" }}30{{ else if eq .stack "staging" }}7{{ else }}1{{ end }}'
})
String Functions
printf
- String Formatting
const bucket = component('storage', 'modules/gcs', {
name: '{{ printf "%s-%s-data" .settings.project_id .stack }}'
// Results in: myproject-dev-data
})
lower
/ upper
- Case Conversion
const resource = component('resource', 'modules/generic', {
name: '{{ .stack | lower }}', // dev, staging, production
label: '{{ .stack | upper }}' // DEV, STAGING, PRODUCTION
})
replace
- String Replacement
const name = component('service', 'modules/app', {
// Replace underscores with hyphens
service_name: '{{ .settings.app_name | replace "_" "-" }}'
})
trim
- Remove Whitespace
const config = component('config', 'modules/config', {
value: '{{ .settings.some_value | trim }}'
})
List and Object Functions
join
- Join List Elements
const firewall = component('firewall', 'modules/firewall', {
// Join list of IPs
source_ranges: '{{ .settings.allowed_ips | join "," }}'
})
split
- Split String
// In stack settings
stack('dev', {
regions_str: 'us-central1,us-east1,us-west1'
})
// Use in component (though JavaScript would be better for this)
const multi_region = component('app', 'modules/app', {
regions: '{{ .settings.regions_str | split "," }}'
})
Default Values
default
- Provide Fallback
const vm = component('vm', 'modules/compute', {
// Use default if not set
machine_type: '{{ .settings.machine_type | default "n1-standard-1" }}',
zone: '{{ .settings.zone | default "us-central1-a" }}'
})
Nested Templates
Access nested settings:
stack('production', {
gcp: {
project_id: 'my-project',
region: 'us-central1'
},
aws: {
region: 'us-west-2',
account_id: '123456789'
}
})
const gcp_resource = component('gke', 'modules/gke', {
project: '{{ .settings.gcp.project_id }}',
region: '{{ .settings.gcp.region }}'
})
const aws_resource = component('eks', 'modules/eks', {
region: '{{ .settings.aws.region }}'
})
Combining JavaScript and Templates
You can combine JavaScript logic with template strings:
// JavaScript for complex logic
const environments = {
dev: { size: 'small', replicas: 1 },
staging: { size: 'medium', replicas: 2 },
production: { size: 'large', replicas: 5 }
}
stack('production', {
env_config: environments['production']
})
// Templates for dynamic values
const app = component('app', 'modules/k8s', {
replicas: '{{ .settings.env_config.replicas }}',
resources: {
size: '{{ .settings.env_config.size }}'
}
})
Common Patterns
Environment-Specific Configuration
const db = component('database', 'modules/cloudsql', {
tier: '{{ if eq .stack "production" }}db-n1-standard-4{{ else }}db-f1-micro{{ end }}',
backup_enabled: '{{ if eq .stack "production" }}true{{ else }}false{{ end }}',
high_availability: '{{ if eq .stack "production" }}REGIONAL{{ else }}ZONAL{{ end }}'
})
Resource Naming
const resources = component('app', 'modules/app', {
// Pattern: project-environment-component
name: '{{ printf "%s-%s-%s" .settings.project_name .stack .component }}',
// Pattern: component-environment
alt_name: '{{ .component }}-{{ .stack }}',
// Pattern: ENVIRONMENT_COMPONENT
env_var_name: '{{ printf "%s_%s" (.stack | upper) (.component | upper) }}'
})
Labels and Tags
const instance = component('vm', 'modules/compute', {
labels: {
environment: '{{ .stack }}',
component: '{{ .component }}',
managed_by: 'comet',
project: '{{ .settings.project_name }}'
}
})
Best Practices
-
Use JavaScript for Complex Logic - Templates are great for simple substitutions, but use JavaScript for complex conditionals and transformations
-
Keep Templates Readable - Break complex templates into multiple lines or use JavaScript variables
-
Validate Template Output - Use
comet export
to see the generated Terraform files and verify template expansion -
Document Template Variables - Add comments explaining what template variables are used and where they come from
// Good: Clear and documented
stack('production', {
// GCP configuration
project_id: 'my-gcp-project', // GCP project ID
region: 'us-central1', // Primary region
// Database configuration
db_tier: 'db-n1-standard-4', // CloudSQL tier
db_version: 'POSTGRES_14' // PostgreSQL version
})