Policy
A policy is a configurable behavior that you attach to a stack. Policies let you define lifecycle rules like automatic cleanup after a time period (TTL) or automatic enforcement of declared state (auto-reconcile).
formae provides two built-in policy types:
- TTL Policy: Automatically destroys a stack and its resources after a specified duration
- Auto-Reconcile Policy: Automatically re-applies the declared state at regular intervals, undoing any out-of-band and incremental changes
Inline vs Reusable Policies
Policies can be defined in two ways:
Inline Policies
Inline policies are defined directly within a stack definition. They are owned by the stack and automatically deleted when the stack is destroyed.
new formae.Stack {
label = "dev-environment"
policies = new Listing {
new formae.TTLPolicy {
ttl = 4.h
onDependents = "cascade"
}
}
}
Inline policies:
- Do not have a label
- Have their lifecycle tied to the owning stack
- Cannot be shared across stacks
Reusable Policies
Reusable policies are defined as standalone objects and referenced by one or more stacks using the .res reference. This lets you define a policy once and apply it consistently across multiple stacks.
// Define a reusable policy
local ephemeralPolicy = new formae.TTLPolicy {
label = "ephemeral-1h"
ttl = 1.h
onDependents = "abort"
}
forma {
// Add the policy to the forma
ephemeralPolicy
// Reference it from multiple stacks
new formae.Stack {
label = "dev-stack-1"
policies = new Listing { ephemeralPolicy.res }
}
new formae.Stack {
label = "dev-stack-2"
policies = new Listing { ephemeralPolicy.res }
}
}
Reusable policies:
- Require an explicit
label - Have an independent lifecycle (must be explicitly deleted)
- Can be shared across multiple stacks via
.resreference - Changes propagate to all referencing stacks
Comparison
| Aspect | Inline | Reusable |
|---|---|---|
| Label | None | Required |
| Lifecycle | Deleted with stack | Independent |
| Sharing | Single stack only | Multiple stacks |
| Use case | One-off behaviors | Consistent policies across stacks |
Querying Policies
Use formae inventory policies to list all reusable policies:
formae inventory policies
Use formae inventory stacks to see which policies are attached to each stack:
formae inventory stacks
Examples
Development environment with TTL:
// Short-lived dev stack that auto-destroys after 8 hours
new formae.Stack {
label = "feature-dev"
description = "Ephemeral development environment"
policies = new Listing {
new formae.TTLPolicy {
ttl = 8.h
onDependents = "cascade"
}
}
}
Production stack with auto-reconcile:
// Production stack that undoes out-of-band and incremental changes every 5 minutes
new formae.Stack {
label = "production-api"
description = "Production API infrastructure"
policies = new Listing {
new formae.AutoReconcilePolicy {
interval = 5.min
}
}
}
Shared policies across environments:
// Reusable policies for consistency
local devTTL = new formae.TTLPolicy {
label = "dev-ttl-24h"
ttl = 24.h
onDependents = "cascade"
}
local prodReconcile = new formae.AutoReconcilePolicy {
label = "prod-reconcile-5m"
interval = 5.min
}
forma {
devTTL
prodReconcile
new formae.Stack {
label = "dev-us-east"
policies = new Listing { devTTL.res }
}
new formae.Stack {
label = "dev-eu-west"
policies = new Listing { devTTL.res }
}
new formae.Stack {
label = "prod-api"
policies = new Listing { prodReconcile.res }
}
}