Skip to content

Getting Started#

This guide walks you through setting up your first nixidy project step by step.

Prerequisites#

  • Nix installed with flakes enabled
  • A Git repository for your Kubernetes manifests
  • Basic familiarity with Kubernetes concepts

What You'll Build#

By the end of this guide, you'll have:

  1. A nixidy project that generates Kubernetes manifests
  2. An nginx deployment with configuration
  3. An Argo CD application ready for GitOps

Step 1: Create Your Project#

Create a new directory for your project:

mkdir my-cluster && cd my-cluster
git init

Step 2: Set Up the Flake#

Create a flake.nix file in your project root:

flake.nix
{
  description = "My Kubernetes cluster managed with nixidy";

  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 {
      # Define your environments
      nixidyEnvs = nixidy.lib.mkEnvs {
        inherit pkgs;

        envs = {
          dev.modules = [./env/dev.nix];
        };
      };

      # Make nixidy CLI available
      packages.nixidy = nixidy.packages.${system}.default;

      # Development shell with nixidy
      devShells.default = pkgs.mkShell {
        buildInputs = [nixidy.packages.${system}.default];
      };
    });
}
Using nixidy without flakes

If you prefer not to use flakes, you can use npins or niv for dependency management.

npins init --bare
npins add github arnarg nixidy --branch main
niv init --no-nixpkgs
niv add github arnarg/nixidy --branch main

Then create default.nix:

default.nix
let
  sources = import ./npins;  # or ./nix/sources.nix for niv
  nixidy = import sources.nixidy {};
in
  nixidy.lib.mkEnvs {
    envs = {
      dev.modules = [./env/dev.nix];
    };
  }

Command syntax

The rest of this guide uses flake syntax (e.g., nixidy build .#dev). Without flakes, omit the .# prefix (e.g., nixidy build dev).

Step 3: Create Your Environment Configuration#

Create the environment directory and configuration file:

mkdir -p env
env/dev.nix
{
  # Where should the generated manifests be stored?
  nixidy.target.repository = "https://github.com/YOUR_USERNAME/my-cluster.git";
  nixidy.target.branch = "main";
  nixidy.target.rootPath = "./manifests/dev";
}

Replace the repository URL

Change YOUR_USERNAME to your actual GitHub username, or use your preferred Git hosting URL.

Step 4: Verify Your Setup#

Enter the development shell and verify everything works:

nix develop
nixidy info .#dev

You should see:

Repository: https://github.com/YOUR_USERNAME/my-cluster.git
Branch:     main

Try building (it will be empty for now):

nixidy build .#dev
tree result

Output:

result
└── apps/

The apps/ folder is empty because we haven't defined any applications yet.

Step 5: Create Your First Application#

Now let's add an nginx application. Update your env/dev.nix:

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

  # Define the nginx application
  applications.nginx = {
    # Deploy to the "nginx" namespace
    namespace = "nginx";

    # Automatically create the namespace
    createNamespace = true;

    # Define Kubernetes resources
    resources = {
      # Deployment
      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;
          };
        };
      };

      # Service
      services.nginx.spec = {
        selector.app = "nginx";
        ports.http.port = 80;
      };
    };
  };
}

Step 6: Build and Inspect#

Build your configuration:

nixidy build .#dev
tree result

You should see:

result
├── apps
│   └── Application-nginx.yaml
└── nginx
    ├── Deployment-nginx.yaml
    ├── Namespace-nginx.yaml
    └── Service-nginx.yaml

Inspect the generated deployment:

cat result/nginx/Deployment-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - image: nginx:1.25.1
          name: nginx
          ports:
            - containerPort: 80
              name: http

Nixidy also generates an Argo CD Application:

cat result/apps/Application-nginx.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx
  namespace: argocd
spec:
  destination:
    namespace: nginx
    server: https://kubernetes.default.svc
  project: default
  source:
    path: ./manifests/dev/nginx
    repoURL: https://github.com/YOUR_USERNAME/my-cluster.git
    targetRevision: main

Step 7: Sync Manifests to Your Repository#

Copy the generated manifests to your repository:

nixidy switch .#dev

This creates the ./manifests/dev directory with all your manifests. Commit and push:

git add .
git commit -m "Initial nixidy configuration"
git push

Step 8: Deploy to Your Cluster#

Option A: Bootstrap with Argo CD#

If you have Argo CD installed, bootstrap all applications with one command:

nixidy bootstrap .#dev | kubectl apply -f -

This creates an "app of apps" that automatically deploys all your applications.

Option B: Apply Directly#

For quick testing without Argo CD:

nixidy apply .#dev

This applies all manifests directly using kubectl apply --prune.

Adding More Resources#

Let's extend the nginx application with a ConfigMap:

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 = {
      # Deployment with ConfigMap volume
      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;
              volumeMounts."/usr/share/nginx/html".name = "html";
            };
            volumes.html.configMap.name = "nginx-html";
          };
        };
      };

      # Service
      services.nginx.spec = {
        selector.app = "nginx";
        ports.http.port = 80;
      };

      # ConfigMap with HTML content
      configMaps.nginx-html.data."index.html" = ''
        <!DOCTYPE html>
        <html>
          <body>
            <h1>Hello from nixidy!</h1>
          </body>
        </html>
      '';
    };
  };
}

Build to see the new ConfigMap:

nixidy build .#dev
cat result/nginx/ConfigMap-nginx-html.yaml

Adding Multiple Applications#

You can define multiple applications in the same file or split them into separate modules:

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

  # First application
  applications.nginx = {
    namespace = "nginx";
    createNamespace = true;
    resources.deployments.nginx.spec = {
      selector.matchLabels.app = "nginx";
      template = {
        metadata.labels.app = "nginx";
        spec.containers.nginx.image = "nginx:1.25.1";
      };
    };
  };

  # Second application
  applications.redis = {
    namespace = "redis";
    createNamespace = true;
    resources.deployments.redis.spec = {
      selector.matchLabels.app = "redis";
      template = {
        metadata.labels.app = "redis";
        spec.containers.redis.image = "redis:7";
      };
    };
  };
}

Project Structure#

A typical nixidy project looks like this:

my-cluster/
├── flake.nix              # Project definition
├── flake.lock             # Locked dependencies
├── env/
│   ├── dev.nix            # Development environment
│   ├── staging.nix        # Staging environment
│   └── prod.nix           # Production environment
├── modules/
│   ├── default.nix        # Common module that imports all applications
│   ├── nginx.nix          # Reusable nginx module
│   └── redis.nix          # Reusable redis module
└── manifests/             # Generated manifests
    ├── dev/
    ├── staging/
    └── prod/

Common Commands#

Command Description
nixidy info .#dev Show environment info
nixidy build .#dev Build manifests to ./result
nixidy switch .#dev Sync manifests to target directory
nixidy bootstrap .#dev Output bootstrap Application YAML
nixidy apply .#dev Apply directly to cluster

Troubleshooting#

"nixidy: command not found"#

Make sure you're in the development shell:

nix develop

Or run nixidy directly:

nix run .#nixidy -- build .#dev

Build fails with type errors#

Nixidy validates your configuration against Kubernetes schemas. Check the error message for the specific field that's incorrect. Common issues:

  • Wrong types (string instead of number)
  • Misspelled field names

Next Steps#

Now that you have a working nixidy project, explore these topics:

Example Repository#

For a complete real-world example, check out arnarg/cluster.