RFC: Optional Alternative Configuration Languages in Atmos
Describe the Feature
Over the years, one of the most surprisingly popular features of Atmos has been templating. What originally started as a small escape hatch — mainly for variable interpolation — has grown into one of the most used (and, honestly, over-used) parts of Atmos.
Speaking personally: I’ve never been a big fan of heavy YAML templating. It’s fragile, hard to validate, and easy to misuse. The multi-phase nature of “render text → then parse YAML” introduces problems that are fundamentally hard to solve:
- validation becomes nearly impossible,
- users can accidentally generate invalid YAML,
- debugging becomes harder,
- the configuration model becomes ambiguous and brittle.
Helm charts suffer from the same issues — it works until it really doesn’t.
Atmos has historically been firm about using YAML for configuration.
But maybe it’s time to acknowledge a simple truth:
The YAML escape hatch has outgrown its original purpose.
It’s become both powerful and problematic.
Proposal
What if Atmos supported alternative syntax for configuration like HCL, Pkl, Starlark, etc.
1. HCL (Terraform Syntax)
Familiar to the community and well-suited to structured configuration.
Pros:
- strong types
- expressive but predictable
- great validation
- good ecosystem support
Would an HCL-powered Atmos config be useful?
- Pkl (Pickle)
A modern configuration language built specifically for typed, validated configuration.
Pros:
- excellent validation
- strict types
- imports/modules
- no templating hacks
- great tooling
Would you adopt Pkl-based stacks?
- TypeScript
A popular choice when teams want flexibility, IDE support, and strong type tooling.
Pros:
- rich language
- massive ecosystem
- autocomplete, intellisense, real-time validation
- easy for frontend/backend engineers
Concerns:
too much power? configuration becoming “code”?
Still, many tools (Next.js, Expo, ESLint, etc.) have moved toward TS configs successfully.
Would a TypeScript-based Atmos DSL feel natural?
- Starlark
Deterministic, Python-inspired, and widely used in Bazel.
Pros:
- predictable
- simple syntax
- safe language
- good middle ground
Would Starlark satisfy your needs?
Why We're Asking
Templating gave users a dynamic escape hatch.
But over time, that escape hatch has become:
- a source of invalid YAML
- hard-to-trace bugs
- a multi-phase evaluation model
- something that undermines validation & correctness
- a de facto programming language inside YAML
Atmos has matured. Its users have matured. And maybe our configuration model should mature too.
But we don’t want to remove the current model or force changes.
We want to offer better, safer alternatives, with a smoother path for teams that want more structure.
Questions for the Community
- Do you feel the same friction with YAML templating?
- Are you interested in optional, alternative configuration languages?
- If we supported multiple syntax backends, which would you prefer?
- HCL
- Pkl
- TypeScript
- Starlark
- Other?
- Would you adopt them incrementally in your stacks?
Your insights will help shape the future design of Atmos configuration.
Thanks for being part of this journey!
YAML Stack Configuration
# stack.yaml
vars:
tenant: tenant1
environment: prod
region: us-west-2
components:
terraform:
vpc:
vars:
cidr_block: "10.0.0.0/16"
eks:
vars:
vpc_id: !terraform.state vpc vpc_id
instance_type: "m6i.large"
desired_capacity: 3
HCL
# stack.hcl
stack "dev" {
vars {
tenant = "tenant1"
environment = "prod"
region = "us-west-2"
vpc_id = atmos::terraform::state("vpc").vpc_id
}
components {
terraform {
component "vpc" {
vars {
cidr_block = "10.0.0.0/16"
}
}
component "eks" {
vars {
instance_type = "m6i.large"
desired_capacity = 3
}
}
}
}
}
Pkl
# stack.pkl
import atmos
stack: atmos.Stack = new atmos.Stack {
atmos = new atmos.Atmos {
terraform = new atmos.TerraformApi {
// Implementation is provided by the Atmos runtime,
// but the *shape* (method signature) is defined in atmos.pkl.
}
}
vars = {
"tenant" = "tenant1"
"environment" = "prod"
"region" = "us-west-2"
"vpc_id" = atmos.terraform.state("vpc")["vpc_id"]
}
components = new atmos.Components {
terraform = new atmos.TerraformComponents {
components = {
"vpc" = new atmos.Component {
vars = {
"cidr_block" = "10.0.0.0/16"
}
}
"eks" = new atmos.Component {
vars = {
"instance_type" = "m6i.large"
"desired_capacity" = 3
}
}
}
}
}
}
Starlark
# stack.star
stack = Stack(
vars = struct(
tenant = "tenant1",
environment = "prod",
region = "us-west-2",
vpc_id = terraform.state("vpc").vpc_id,
),
components = Components(
terraform = TerraformComponents(
components = {
"vpc": Component(
vars = {
"cidr_block": "10.0.0.0/16",
},
),
"eks": Component(
vars = {
"instance_type": "m6i.large",
"desired_capacity": 3,
},
),
},
),
)
)
Typescript
// stack.config.ts
export const stack: StackConfig = defineStack({
vars: {
tenant: "tenant1",
environment: "prod",
region: "us-west-2",
vpc_id: terraform.state("vpc").vpc_id as string,
},
components: createComponents(
createTerraformComponents({
vpc: createComponent({
cidr_block: "10.0.0.0/16",
}),
eks: createComponent({
instance_type: "m6i.large",
desired_capacity: 3,
}),
}),
)
});
Is asking for both HCL and some real-life language too much?
I understand that people might feel familiar with HCL, but me personally - I hate it. It always seemed more as a hack, than a language.
My preference would be Starlark, but someone from our team would prefer TS. Personally - typescript here also sucks - why all the extra stuff I have to type "export const stack"... yes I understand it comes from the language, but it's too much IMO.
@mtb-xt I think if there's enough interest, we can add multiple.
We have an initial stab at this here:
- cloudposse/atmos#1842
It implements a stack loader registry which supports a pluggable way of load stacks. This means adding other formats would be straightforward.
It also implements a method to convert from YAML/HCL/JSON<->YAML/HCL/JSON.
I think the bigger risk fractured documentation, and that there will naturally be things you can do in one language and not in another.
I think the bigger risk fractured documentation, and that there will naturally be things you can do in one language and not in another.
That's the reason why I gave up on the idea of using Pulumi: Community fragmentation due to various supported languages, and suboptimal support of the language I was interested in compared to some others.