Skip to main content
A policy is a lifecycle rule you attach to a stack. Where a forma declares what resources should exist, a policy declares how formae manages the stack over time on its own, without you running apply again. There are two:
  • TTL: destroy the stack after a duration, for ephemeral environments.
  • Auto-reconcile: re-apply the declared state on an interval, so drift never sticks.
You attach a policy one of two ways:
  • Inline, declared directly on a single stack. It belongs to that stack and is deleted with it.
  • Reusable (standalone), defined once with a label and referenced from any number of stacks. Edit it in one place and every stack that references it picks up the change.
The Policy concept covers the trade-offs in full. This guide shows how to attach both kinds.
1

Attach an inline policy

Add a policies listing to the stack. A TTL policy expires it after a duration:
Or keep the stack pinned to its declared state with auto-reconcile:
Declare the policy inside your stack’s complete forma, alongside its resources. Reconcile compares the whole stack, so applying a forma that holds only the policy would remove the stack’s resources.
2

Share one policy across stacks

To apply the same rule to several stacks, give the policy a label and define it once at the top of the forma, then reference it from each stack with .res:
Change ttl in the one definition and both stacks pick it up on the next apply.
3

Apply

  formae apply · reconcile                                                                          your-infra.pkl
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  + 3 create

  ▌ Policies
  Operation ▲   Label                                   Type                Stack
  + create      ephemeral-24h                           ttl                 
  + create      ephemeral-24h                           ttl                 dev-sandbox-1
  + create      ephemeral-24h                           ttl                 dev-sandbox-2

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  ↑↓: select  space: expand  →←: column  s: sort  y: confirm  q: abort This operation will create 1 policy(ies).  Do
you want to continue? (y/N)  ?: help
The plan shows the policy being created and attached to each stack (for the reusable example above, create policy ttl ephemeral-24h, then attach ephemeral-24h to dev-sandbox-1 and attach ephemeral-24h to dev-sandbox-2). From then on formae enforces it: TTL destroys the stack when the duration elapses; auto-reconcile hard-reconciles on every interval.
4

Verify

Reusable policies and the stacks they are attached to show in:
  formae inventory
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                                         ╭────────────╮
  1 Resources    2 Targets    3 Stacks    4 Policies 
─────────────────────────────────────────╯            ╰─────────────────────────────────────────────────────────────

Label ▲             Type                AttachedStacks                
──────────────────────────────────────────────────────────────────────
ephemeral-24h       ttl                 dev-sandbox-1, dev-sandbox-2  

Showing 1 of 1 policies
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  /: query
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  ↑↓/j/k: navigate  enter: detail  /: search  s: sort  r: refresh  1-4: tab  q: quit                       ?: help
Inline policies have no independent identity, so to see the policy on a given stack, check the stack itself:
  formae inventory
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                             ╭──────────╮
  1 Resources    2 Targets    3 Stacks    4 Policies 
─────────────────────────────╯          ╰───────────────────────────────────────────────────────────────────────────

Label ▲                   Description                                     Policies                            
──────────────────────────────────────────────────────────────────────────────────────────────────────────────
dev-sandbox-1             Sandbox for the payments team                   TTL: 1d, expires in 23h58m (ephemer…
dev-sandbox-2             Sandbox for the checkout team                   TTL: 1d, expires in 23h58m (ephemer…

Showing 2 of 2 stacks
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  /: query
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  ↑↓/j/k: navigate  enter: detail  /: search  s: sort  r: refresh  1-4: tab  q: quit                       ?: help
A TTL with onDependents = "cascade" deletes resources in other stacks if they depend on this one, anywhere the dependency chain leads. Use the default abort unless you are certain nothing outside the stack should survive it.

See also