Build-Time / DevOps DSLs Family Index


type: language-family-index family: build-devops languages_catalogued: 32 tags: [language-reference, family-index, build, devops, ci-cd, kubernetes, deployment]

Build-Time / DevOps DSLs — Family Index

Family overview

Build-time and DevOps DSLs cover the long tail of “languages no one calls a language but everyone writes” — the files that decide what gets built, in what order, in which container, and on which cluster. They form a layered spectrum. At the bottom sit file-target build tools (Make, Ninja, SCons) whose mental model is “given source file X, produce target Y, here’s the recipe.” Above them are the hermetic monorepo build systems (Bazel, Buck2, Pants, Please) — content-addressed, parallel, remote-cacheable engines that demand strict dependency declarations in exchange for sub-second incremental rebuilds across thousands of targets. In a separate cluster are task runners (Just, Task, Mage, doit, Rake, Cake, FAKE) — modern Make-replacements whose job is not to track file dependencies but to give engineers a discoverable, ergonomic CLI of named commands. Above all of those, containerized pipeline-as-code (Earthly, Dagger, Tilt) lifts the entire build into a reproducible container graph, and CI YAML (GitHub Actions, GitLab CI, CircleCI, Jenkins, Argo, Tekton) wires the whole machine into a triggered workflow. Crowning the stack are K8s manifest DSLs (Helm, Kustomize, Skaffold) and multi-cloud provisioning (CDK, Pulumi) that turn application packaging into a declarative artifact.

The recurring tension across the whole family is expressiveness vs. determinism. Bazel’s Starlark is deliberately a non-Turing-complete Python subset — no while, no recursion, no I/O — because the build engine needs to evaluate millions of rules deterministically and cache the results. CI YAML went the opposite way: pure declarative configuration that’s trivially parseable but rapidly unreadable once it grows past two screens of conditionals and matrix expansions. Helm’s Go-template-over-YAML is the worst-of-both-worlds outcome of that path — whitespace-fragile templating producing whitespace-significant YAML — and it’s the de facto K8s packaging format anyway.

The 2020s answer to YAML fatigue has been “use a real language.” Pulumi (2018) launched the wave for IaC, AWS CDK (2019) brought it to CloudFormation, CDK8s (2020) to Kubernetes manifests, and Dagger (2022) extended it to CI pipelines themselves — write your build/test/deploy graph in Go, Python, TypeScript, or Java, get type-checking, IDE completion, and unit tests for free. Earthly took the middle path: a DSL deliberately shaped like a hybrid of Make and Dockerfile, because containers turned out to be the lingua franca everyone agreed on. Whether the “real language” thesis kills YAML in CI the way HCL killed YAML in IaC is still open in 2026; GitHub Actions YAML’s network effect is enormous.

In our deep library

None of the tools in this family have dedicated deep notes — they’re build/DevOps DSLs rather than general-purpose languages. Cross-reference these:

  • config-and-dsl — already catalogues CMake, Make, Ninja, Meson, Bazel, Buck2, SCons, Earthly, Helm, Kustomize, HCL, Pulumi, Starlark, Nix, Dhall. This index extends that work in the workflow / pipeline / CI direction; treat the two as complementary.
  • groovy — Jenkinsfile and Gradle are Groovy-hosted DSLs.
  • ruby — Rake is a Ruby internal DSL; Chef recipes too.
  • python — SCons, Pants, doit, Meson all use Python or Python-flavored frontends.
  • fsharp — FAKE (“F# Make”) is an F# build DSL.
  • csharp — Cake (“C# Make”) and AWS CDK / Pulumi .NET targets.
  • go — Mage, Task, Dagger Go SDK, Pulumi Go, CDK Go, Buildkit, Helm itself, Tekton.
  • rust — Just is Rust-implemented; Buck2 is Rust-rewritten.
  • typescript — AWS CDK, Pulumi, Dagger TS SDK, CDK8s.

Tier 3 family table

Tool / DSLFirst appearedLanguage familyDomainStatus (2026)URL
GNU Make1988 (Make: 1976)Make-family DSL (tabs + macros + shell)File-target build, universal orchestratorUniversal, immortalhttps://www.gnu.org/software/make/manual/
BSD make1980sMake-family DSL (different macro/conditional syntax)BSD / pkgsrc buildsActive in BSDshttps://man.freebsd.org/cgi/man.cgi?make(1)
NMAKE1987Make-family DSL (Microsoft variant)MSVC builds, Win32 SDKMature, declininghttps://learn.microsoft.com/en-us/cpp/build/reference/nmake-reference
Bazel BUILD + Starlark (.bzl)2015 (open-sourced from Blaze 2006)Starlark (deterministic Python subset)Hermetic monorepo build, remote cache + RBEActive, dominant in its nichehttps://bazel.build/
Buck22023 (Buck1: 2013)Starlark front-end, Rust DAG engineMeta’s Bazel-class rewriteActivehttps://buck2.build/
Pants 22020 (Pants 1: 2014)Python BUILD files + Starlark-ish rulesPolyglot monorepo build (Python, Go, Java, Scala)Activehttps://www.pantsbuild.org/
Please.build2017Go-implemented, BUILD files in Skylark/Starlark dialectBazel-flavored cross-language buildActive, nichehttps://please.build/
Earthly (Earthfile)2020Hybrid Make + Dockerfile DSLContainerized portable buildActivehttps://earthly.dev/
Dagger SDK2022Real languages: Go / Python / TypeScript / Java / .NETContainerized pipeline-as-code; runs on BuildkitActive, growinghttps://dagger.io/
Tilt2018Starlark (Tiltfile)K8s inner dev loop (live-reload into clusters)Activehttps://tilt.dev/
Just2017Make-influenced DSL, Rust-implementedPer-project task runner / command discoveryActive, very popularhttps://just.systems/
Task2017YAML (Taskfile.yml), Go-implementedCross-platform task runnerActive, growinghttps://taskfile.dev/
Mage2018Go (mage targets are Go funcs)Go-native make replacementActive, nichehttps://magefile.org/
doit2008Python (tasks are Python functions)Build/automation in Python projectsMaturehttps://pydoit.org/
Rake2003Ruby internal DSLRuby-world build / task runnerMature, ubiquitous in Rubyhttps://ruby.github.io/rake/
Cake2014C# DSL (cake script + addins).NET build automationActivehttps://cakebuild.net/
FAKE2009F# DSL (“F# Make”).NET build automation, F# flavorActive, nichehttps://fake.build/
SCons2000Python (SConstruct is a Python program)Python-as-build-DSLMaturehttps://scons.org/
Ninja2012Minimal low-level build descriptionBackend for CMake/Meson/gn; fastest incrementalUniversal as backendhttps://ninja-build.org/
Meson2013Python-flavored DSL, Ninja backendModern meta-build (GNOME, systemd, GStreamer)Active, growinghttps://mesonbuild.com/
CMake2000CMake DSL → Ninja/Make/MSBuild/XcodeC/C++ meta-build (cross-ref config-and-dsl)Dominant in C/C++https://cmake.org/cmake/help/latest/
Helm chart templates2016Go templates over YAMLK8s packagingDominanthttps://helm.sh/docs/
Kustomize2018Pure YAML strategic-merge + patchesK8s overlay configDominant alongside Helm; built into kubectlhttps://kustomize.io/
Skaffold2018YAMLK8s build/push/deploy inner loopActivehttps://skaffold.dev/
AWS CDK2019TS / Python / Go / Java / C# / .NETSynthesizes CloudFormation from real codeActive, dominant in AWS shopshttps://docs.aws.amazon.com/cdk/v2/guide/home.html
Pulumi2018TS / Python / Go / .NET / Java / YAMLMulti-cloud IaC in real languagesActivehttps://www.pulumi.com/docs/
Dockerfile2013Dockerfile DSL (instructions + shell)Container image buildUniversalhttps://docs.docker.com/engine/reference/builder/
Containerfile (Buildah/Podman)2017Dockerfile-compatible DSLDaemonless OCI image buildActivehttps://github.com/containers/common/blob/main/docs/Containerfile.5.md
Buildkit LLB2018Low-level Build (Go protobuf graph + frontends)Buildkit’s IR; Dockerfile is a frontend, others possibleUniversal as backendhttps://github.com/moby/buildkit
GitHub Actions YAML2019YAML (workflows + reusable actions)Hosted CI/CDDominanthttps://docs.github.com/en/actions
GitLab CI YAML2015YAML (.gitlab-ci.yml)GitLab-hosted CI/CDDominant in GitLab shopshttps://docs.gitlab.com/ee/ci/yaml/
Jenkinsfile2016Groovy DSL (declarative or scripted)Self-hosted CI/CD (cross-ref groovy)Mature, declining but huge install basehttps://www.jenkins.io/doc/book/pipeline/jenkinsfile/
CircleCI config YAML2014YAML (.circleci/config.yml)Hosted CI/CD; orbs for reuseActivehttps://circleci.com/docs/configuration-reference/
Argo Workflows2017YAML (K8s CRDs)DAG / step workflow on KubernetesActive, CNCF graduatedhttps://argo-workflows.readthedocs.io/
Tekton2019YAML (K8s CRDs: Task / Pipeline / PipelineRun)K8s-native CI/CD primitivesActive, CNCF graduatedhttps://tekton.dev/

Notable threads

  • The hermetic-monorepo cluster (Bazel / Buck2 / Pants / Please). All four picked Starlark or a near-Starlark dialect because the engine needs to evaluate millions of rules deterministically and cache them by content hash. Starlark’s deliberate amputations (no while, no recursion, no I/O, no global mutability) are the point: they let the engine treat rule evaluation as a pure function. Buck2 (Rust, 2023) is Meta’s bet that the original Buck/Bazel engine architecture was right but the implementation could be 5–10x faster; Pants 2 (2020) is the rewrite that made the design palatable to Python and JVM monorepos that didn’t want Google’s tooling tax.

  • The “use a real language” thesis. Pulumi (2018) → AWS CDK (2019) → CDK8s (2020) → Dagger SDK (2022) is a single arc: every successive layer of YAML got a “write it in TS/Python/Go/Java instead” answer, motivated by the same complaints (no types, no IDE completion, no unit tests, no abstraction beyond YAML anchors). Whether this kills CI YAML the way HCL killed YAML for cloud provisioning is the open question of 2026.

  • Earthly and Dagger as containerized portable pipelines. Both treat the container as the unit of reproducibility. Earthly invented a DSL that fuses Makefile targets with Dockerfile syntax; Dagger went further and embedded the pipeline graph in a real language SDK that compiles to Buildkit LLB. Both replace the “works on my machine, fails in CI” problem with a graph that runs identically locally and in any CI provider — which sidesteps lock-in to GitHub Actions / GitLab CI / Jenkins specifics.

  • GitHub Actions YAML won the CI war despite obvious limitations. It’s not the most expressive (Jenkins Groovy), not the fastest (Buildkit-native systems), not the most reproducible (Earthly/Dagger), and not the most type-safe (Dagger SDKs). It won because GitHub is where the code is, the Marketplace gave it an enormous reusable-action ecosystem, and uses: actions/checkout@v4 is one line. Network effects beat language design — again.

  • K8s YAML escape hatches. Helm’s Go-template-over-YAML is widely hated (whitespace-fragile templating producing whitespace-significant YAML), and the alternatives split three ways: Kustomize (no templating, pure overlay merging — built into kubectl), CDK8s / cdk8s+ (synthesize manifests from TypeScript/Python/Go/Java), and typed-config replacements (KCL, Cue, Pkl from config-and-dsl). Helm’s chart-repo network effect keeps it dominant despite the language complaints.

  • The Just / Task / Mage cluster as the modern Make-replacement. None of the three try to be a build system — they’re task runners, focused on the “type a command, run a recipe” use case Make also handles but with worse ergonomics (tabs! shell quoting! unintuitive variable expansion!). Just (Rust, 2017) won on UX polish and cross-platform portability. Task (Go, YAML, 2017) won the YAML-friendly crowd. Mage (Go, 2018) won the “I want my targets to be Go code” crowd. Rake (Ruby, 2003) and FAKE/Cake (.NET, 2009/2014) are the older language-native versions of the same idea.

  • Argo and Tekton: K8s-native CI primitives. Both are CNCF-graduated. Both express pipelines as Kubernetes Custom Resource Definitions, so the cluster’s scheduler runs the pipeline. Argo Workflows is more general (any DAG of pods); Tekton is more CI-focused (Tasks compose into Pipelines into PipelineRuns). They’re the answer to “what if your CI server is your Kubernetes cluster,” and they underpin most of the modern GitOps stack (Argo CD, Flux).

Citations