Skip to content
Dev Tools Tutorial

nixidy: Ditch the 600-Line Helm Values File, Use Nix Instead

nixidy replaces Helm overrides, Kustomize overlays, and raw YAML with typed Nix expressions — turning Kubernetes manifest authoring into something closer to configuring a NixOS system.

AI
DevClubHouse Curation
Jun 8, 2026 · 4 min read · 0 comments

If you've managed a Kubernetes GitOps repo long enough, you've hit the wall: a Helm values override file that has grown to 600 lines, helm template | grep archaeology, and a lingering uncertainty about what actually landed in the cluster. nixidy is a tool written specifically to close that gap — replacing the Helm/Kustomize layer with a single Nix expression per environment whose output is plain, diffable YAML.

The Rendered Manifests Pattern

nixidy implements the Rendered Manifests Pattern: your CI evaluates Nix expressions and commits the resulting YAML to a branch, ArgoCD pulls that YAML and applies it, and you review concrete diffs in pull requests before anything touches a cluster. The deployment side is identical to running ArgoCD against raw YAML — nixidy only changes how that YAML is produced.

The key structural shift is that every Kubernetes resource becomes a typed Nix option, not a freeform string blob. A Deployment has an integer replicas, a string image, and a selector that's a structured attribute set. Set replicas = "two" and the build fails immediately — not 15 minutes into a rollout.

Wiring Up the Flake

The entry point is a flake.nix that pulls in nixidy and declares named environments:

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    nixidy.url = "github:arnarg/nixidy";
  };

  outputs = { nixpkgs, flake-utils, nixidy, ... }:
    flake-utils.lib.eachDefaultSystem (system:
      let pkgs = import nixpkgs { inherit system; };
      in {
        nixidyEnvs = nixidy.lib.mkEnvs {
          inherit pkgs;
          envs.dev.modules = [ ./env/dev.nix ];
        };
      });
}

nixidy.lib.mkEnvs produces Nix derivations — one per named environment — that build the full set of YAML manifests. Each environment takes a list of modules using the exact same NixOS module system: imports, lib.mkDefault, lib.mkForce, the whole composition toolkit.

Writing an Environment Module

An environment module looks like this (env/dev.nix):

{
  nixidy.target.repository = "https://github.com/YOUR_USERNAME/my-cluster.git";
  nixidy.target.branch = "main";
  nixidy.target.rootPath = "./manifests/dev";

  applications.nginx = {
    namespace = "nginx";
    createNamespace = true;
    resources = {
      deployments.nginx.spec = {
        replicas = 2;
        selector.matchLabels.app = "nginx";
        template = {
          metadata.labels.app = "nginx";
          spec.containers.nginx = {
            image = "nginx:1.25.1";
            ports.http.containerPort = 80;
          };
        };
      };
      services.nginx.spec = {
        selector.app = "nginx";
        ports.http.port = 80;
      };
    };
  };
}

A few things worth noting here:

  • nixidy.target.* tells nixidy where to write YAML and what path to embed in the generated ArgoCD Application manifests.
  • applications.nginx is a logical grouping that produces both the Kubernetes resources and an ArgoCD Application manifest pointing at them — no hand-authored Application YAML required.
  • createNamespace = true emits a Namespace manifest automatically. Without it, you'd create the namespace out-of-band and pray nothing drifts.

To build:

nix run github:arnarg/nixidy -- build .#dev

The output is a result/ tree with an apps/ directory containing Application-nginx.yaml and a nginx/ directory with the Deployment, Service, and Namespace manifests — ready to commit and push.

Composition Is the Real Payoff

The single biggest advantage over Helm values or Kustomize patches shows up when you add environments. A prod.nix that scales up one application:

{ lib, ... }: {
  imports = [ ./dev.nix ];
  applications.nginx.resources.deployments.nginx.spec.replicas =
    lib.mkForce 10;
}

Two lines. No duplicated YAML, no strategic-merge patch gymnastics, no helm upgrade --set. lib.mkForce is the same override mechanism NixOS uses to let a module win a value conflict — you get it for free because nixidy is built on the NixOS module system.

If you've already internalized how NixOS modules compose, managing a multi-environment Kubernetes fleet with nixidy will feel immediately familiar. If you haven't, this is a compelling reason to learn — the same mental model now scales from your laptop's system config to a production cluster's full workload manifest.

nixidy is an early project, and the source material covers only the introductory setup — but the primitives on display (typed resources, environment composition, automatic ArgoCD manifest generation) address real, daily pain points that Helm and Kustomize have never fully solved.

Discussion 0

Join the discussion

Sign in with GitHub to comment and vote.

Sign in with GitHub

No comments yet

Be the first to weigh in.

Related Reading