Share configuration with a vars module
Most projects reuse the same stack and target across several formae. Put those in a plain Pkl module and import it wherever you need them.vars.pkl and
every forma that imports it picks up the new value.
Group resources into a class
When several resources always travel together, a VPC with its subnets and route table, wrap them in a Pkl class. The class takes its inputs as typed fields, builds the resources withhidden, and exposes them as a single resources
listing.
hiddenkeeps each resource internal to the class. Only theresourceslisting needs to be consumed from outside.vpc.res.idis a resolvable. Inside the class the subnet references the VPC’s ID, and formae works out that the VPC has to be created first.- The class exposes one thing worth reading:
resources, a listing formae knows how to apply.
...
operator expands the listing into individual resources:
Compose classes
Layered infrastructure is where classes pay off. Build the networking layer, then pass its resources into a class that needs them. A field typed as a resource accepts an instance produced by another class, and the receiving class reads properties off it with.res.
Reference parent fields with outer
When one class nests another, useouter inside the inner definition to reach a
field on the enclosing class. This lets a top-level class thread a single input,
like a region or an account ID, down into the resources it builds without
repeating it.
Prefer functions for straightforward creation
If a module just produces resources from inputs without composing layers, a function is lighter than a class. A function takes its inputs as arguments and returns either a single resource or aListing.
Apply as usual
Modules and classes are an authoring convenience. By the time formae sees your forma, the class fields and function calls have resolved to a flat set of resources, so applying works exactly as it does for a single-file forma. formae apply · reconcile main.pkl
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
+ 15 create
▌ Targets
Operation ▲ Label
+ create aws-target
▌ Stacks
Operation ▲ Label
+ create lifeline
▌ Resources
Operation ▲ Label Type
+ create lifeline-vpc AWS::EC2::VPC
+ create lifeline-igw AWS::EC2::InternetGateway
+ create lifeline-igw-attachment AWS::EC2::VPCGatewayAttachment
+ create lifeline-public-subnet-1 AWS::EC2::Subnet
+ create lifeline-public-subnet-2 AWS::EC2::Subnet
+ create lifeline-public-rt AWS::EC2::RouteTable
+ create lifeline-public-route AWS::EC2::Route
+ create lifeline-public-subnet-1-assoc AWS::EC2::SubnetRouteTableAssociation
+ create lifeline-public-subnet-2-assoc AWS::EC2::SubnetRouteTableAssociation
+ create lifeline-alb-sg AWS::EC2::SecurityGroup
↓ show 10 more (3 remaining)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
↑↓: select space: expand →←: column s: sort y: confirm q: abort This operation will create 1 stack(s), create
1 target(s) and create 13 resource(s). Do you want to continue? (y/N) ?: help
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
+ 15 create
▌ Targets
Operation ▲ Label
+ create aws-target
▌ Stacks
Operation ▲ Label
+ create lifeline
▌ Resources
Operation ▲ Label Type
+ create lifeline-vpc AWS::EC2::VPC
+ create lifeline-igw AWS::EC2::InternetGateway
+ create lifeline-igw-attachment AWS::EC2::VPCGatewayAttachment
+ create lifeline-public-subnet-1 AWS::EC2::Subnet
+ create lifeline-public-subnet-2 AWS::EC2::Subnet
+ create lifeline-public-rt AWS::EC2::RouteTable
+ create lifeline-public-route AWS::EC2::Route
+ create lifeline-public-subnet-1-assoc AWS::EC2::SubnetRouteTableAssociation
+ create lifeline-public-subnet-2-assoc AWS::EC2::SubnetRouteTableAssociation
+ create lifeline-alb-sg AWS::EC2::SecurityGroup
↓ show 10 more (3 remaining)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
↑↓: select space: expand →←: column s: sort y: confirm q: abort This operation will create 1 stack(s), create
1 target(s) and create 13 resource(s). Do you want to continue? (y/N) ?: help
--yes to skip the confirmation prompt in
a CI/CD job.
See also
- Build self-service infrastructure: a full class-based offering exposed to developers through property flags.
- Resolvable: how
.resreferences let resources depend on each other, including across classes. - Properties: parameterize a module’s inputs as CLI flags.
- Stack: how the resources you compose are grouped and reconciled together.
- Apply modes: reconcile versus patch once your composed forma is ready to apply.

