So... how's your YAML life going?
If you work with tools like Ansible Playbooks, Docker Compose, or especially Kubernetes manifests, chances are you're knee-deep in YAML files every day.
In many real-world projects, we often need to generate multiple variations of Kubernetes manifests for different environments (like dev, staging, and production). Tools like Helm and Kustomize were created to manage exactly this use case.
But these tools aren't without problems. Ever wrestled with fixing invalid YAML output from a Helm template? Or struggled with the patch ordering puzzle in Kustomize? If you've felt that pain, this article introduces a solution: injecting Lisp-style functional power into your YAML.
When Helm and Kustomize Aren’t Enough
Helm
Helm is a popular templating tool for Kubernetes that uses Go's text/template
to generate YAML manifests.
Strengths:
- Well-suited for generating large sets of manifests.
- Allows for toggling features on and off using conditional logic.
Limitations:
- Templates treat YAML as raw text, not structured data.
- Output can become invalid YAML if the template is miswritten.
Kustomize
Kustomize introduces a clear semantic model for manipulating Kubernetes manifests through the concepts of resources, generators, and transformers.
Strengths:
- Provides a semantic, Kubernetes-aware way to apply changes to manifests.
- Strong reuse capabilities thanks to clean layering and patching mechanics.
Limitations:
- Can’t easily generate resources or toggle their inclusion—it's designed to modify existing bases, not build them from scratch.
- Unintended use cases (e.g. patching beyond its intended scope) often result in puzzle-like configurations.
- Higher learning curve compared to Helm.
- Its model is tightly coupled to Kubernetes, making its concepts hard to transfer to other YAML-based tools.
So What's the Alternative?
What we really need is:
- Variable injection and toggling structures on/off
- Clear evaluation order
- The ability to embed logic directly without leaving YAML's structure
We want a way to treat YAML as data, while also injecting code into that data. Sounds impossible?
Yes, It’s LISP
Lisp, born in 1960, is one of the oldest programming languages. You may have seen memes about "Lisp aliens", but don't let that distract you.
Lisp is still relevant—especially because of this trait:
Code and data share the same structure.
Here's a minimal Lisp example:
(+ 3 5) ; This is both data (a list) and code (an addition)
This flexibility is exactly what we want in our YAML: to represent structured configuration and logic as one.
Injecting Lisp into YAML: Meet yisp
Enter yisp
, a tool that lets you write Lisp-like expressions inside YAML.
Consider this example:
myaddition: !yisp
- +
- 3
- 5
This will be evaluated into:
myaddition: 8
The !yisp
tag marks the list as a yisp expression. Like Lisp, it's prefix notation: ['+', 3, 5]
means 3 + 5
.
Writing Reusable Templates
You can define reusable templates as functions:
!yisp &mkpod
- lambda
- [name, image]
- !quote
apiVersion: v1
kind: Pod
metadata:
name: *name
spec:
containers:
- name: *name
image: *image
Then invoke it like this:
!yisp
- *mkpod
- mypod1
- myimage1
Which yields:
apiVersion: v1
kind: Pod
metadata:
name: mypod1
spec:
containers:
- name: mypod1
image: myimage1
The YAML anchor (&
) and alias (*
) features are used here like let
and variable references.
Kustomize-Like Functionality
Want to load all files from a directory and generate a ConfigMap? Sure:
apiVersion: v1
kind: ConfigMap
metadata:
name: my-config
data: !yisp
- from-entries
- - map
- - lambda
- [file]
- !quote
- *file.name
- *file.body
- - read-files
- ./cm-files/*
This is similar to Kustomize's configMapGenerator
, but written clearly and explicitly using standard YAML and yisp's expressive power.
What About More Complex Logic?
Yes, yisp is powerful—but not everything should be written inside YAML. When logic gets too complex, you can offload it to Go and call it from yisp.
For example, you can use a Helm adapter written in Go to expand a chart:
!yisp &helm-chart
- lambda
- [!helm-chart-props props]
- - go-run
- pkg: github.com/totegamma/yisp-helm-adapter@v0.1.0
args:
- *props.repo
- *props.release
- *props.version
stdin:
- to-yaml
- *props.values
And then:
!yisp
- *helm-chart
- repo: "https://charts.concrnt.net/"
release: "concrnt"
version: "0.7.13"
values:
meilisearch:
enabled: true
Conclusion: Code and Data, Together
yisp
enables a new way to manage configuration:
- Structured YAML
- Functional logic
- Native integration
And the best part? It's not just for Kubernetes. If your tool can read YAML, it can work with yisp. You get the expressive power of code, without abandoning YAML.
yisp
is still under development, but it's OSS and ready for real-world use. Try it out, build something, and let us know what you think!
Top comments (2)
Pretty cool to see people add this kind of power to plain YAML stuff, especially after all the headaches I’ve had with templates before.
Thanks for reading! Glad it resonated. 🙌