DEV Community

Cover image for What If YAML and Lisp Had a Child?: Bring Functional Power to Your Kubernetes Manifests
totegamma
totegamma

Posted on

What If YAML and Lisp Had a Child?: Bring Functional Power to Your Kubernetes Manifests

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

This will be evaluated into:

myaddition: 8
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Then invoke it like this:

!yisp
- *mkpod
- mypod1
- myimage1
Enter fullscreen mode Exit fullscreen mode

Which yields:

apiVersion: v1
kind: Pod
metadata:
  name: mypod1
spec:
  containers:
    - name: mypod1
      image: myimage1
Enter fullscreen mode Exit fullscreen mode

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/*
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

And then:

!yisp
- *helm-chart
- repo: "https://charts.concrnt.net/"
  release: "concrnt"
  version: "0.7.13"
  values:
    meilisearch:
      enabled: true
Enter fullscreen mode Exit fullscreen mode

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!

GitHub: https://github.com/totegamma/yisp

Top comments (2)

Collapse
 
nevodavid profile image
Nevo David

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.

Collapse
 
totegamma profile image
totegamma

Thanks for reading! Glad it resonated. 🙌