Karya Semi
HomeBlogSearchCategoriesAboutContact
Karya Semi

Less noise. More notes.

HomeBlogAboutContactPrivacy PolicyDisclaimer

© 2026 Karya Semi. All rights reserved.

XGitHubLinkedIn
  1. Home
  2. /Categories
  3. /Programming

Running NixOS on NVIDIA's DGX Spark: Reproducible AI Workstations Done Right

How to set up NixOS on NVIDIA's DGX Spark for reproducible AI development environments. Declarative config, flakes, CUDA drivers, and why NixOS solves the 'works on my machine' problem for ML engineers.

Dian Rijal Asyrof/August 3, 2026/6 min read
Illustration for Running NixOS on NVIDIA's DGX Spark: Reproducible AI Workstations Done Right

If you've ever lost half a day debugging a CUDA version mismatch between your local machine and a training server, you already know the pain. Different driver versions, conflicting Python packages, someone installed a system-level library three months ago and forgot about it. The classic response is Docker, and Docker works fine for a lot of things. But Docker doesn't solve the OS layer. It doesn't handle your NVIDIA drivers, your kernel modules, your system-level dependencies. You end up with a container image that's reproducible, sitting on top of an OS that absolutely isn't.

NixOS does. And running it on NVIDIA's DGX Spark turns this compact AI workstation into something genuinely reproducible, from kernel to CUDA toolkit to your Python environment.

What the DGX Spark Actually Is

The DGX Spark is NVIDIA's desktop-class AI workstation. It ships with a Grace Blackwell GB10 superchip, 128GB of unified memory, and NVLink connectivity all in a small form factor. NVIDIA positions it as a developer box for training and inference on models that don't quite justify cloud GPU spend, or for teams that need local iteration speed.

It ships with Ubuntu. That's fine. Ubuntu works. But if you've ever managed a fleet of Ubuntu machines for ML work, you know the drift problem. One developer installs a PPA for a newer CUDA toolkit. Another edits /etc/ld.so.conf by hand. Six months later, nobody can reproduce the original environment. The machine works, but only on that machine, in that state, at that point in time.

NixOS eliminates that entire class of problems. Your entire system configuration lives in a single set of files. Rebuild those files on a different machine, you get the same system. Byte-for-byte, package-for-package.

NixOS in 60 Seconds

For the uninitiated: NixOS is a Linux distribution built around the Nix package manager. Instead of imperatively installing packages with apt install or pacman -S, you declare what you want in a configuration file and rebuild the system.

# configuration.nix (simplified)
{ config, pkgs, ... }:
{
  environment.systemPackages = with pkgs; [
    git
    vim
    python311
    cudatoolkit
  ];
 
  services.openssh.enable = true;
}

Run nixos-rebuild switch, and the system converges to that declaration. Every package version is tracked. Rollbacks are instant because previous generations are preserved. And critically, you can check this file into git and have a complete, auditable history of every system change.

The key insight: NixOS treats your operating system as code. Not metaphorically. Literally. It's a pure function from configuration to system state.

DGX Spark + NixOS: The Hardware Setup

Getting NixOS onto the DGX Spark requires a few specific steps because the hardware is new enough that not everything lands cleanly out of the box. Here's what I've found works.

Boot media. Grab the latest NixOS ISO (24.11 or unstable). The DGX Spark uses UEFI, so the standard UEFI installer works. You'll want to set the boot mode to UEFI-only in the firmware settings before starting.

Storage layout. The Spark ships with NVMe storage. I typically go with a straightforward partition scheme:

# hardware-configuration.nix (snippet)
fileSystems."/" = {
  device = "/dev/disk/by-label/nixos";
  fsType = "ext4";
};
 
fileSystems."/boot" = {
  device = "/dev/disk/by-label/boot";
  fsType = "vfat";
};

If you want encryption (and you probably should for a workstation that'll hold model weights and API keys), use LUKS. NixOS has first-class support for it in the installer.

Network. The Spark's networking stack works with the default kernel. Nothing special needed here.

NVIDIA Drivers and CUDA: The Part Everyone Worries About

This is where most people expect trouble, and honestly, it's where NixOS shines brightest for this use case.

On a traditional distro, getting NVIDIA drivers right means coordinating between the driver package, the CUDA toolkit, cuDNN, and sometimes NCCL. Version mismatches between any of these will silently break things. You'll get a PyTorch build that imports fine but segfaults at runtime.

On NixOS, you declare the driver and CUDA versions in your config, and Nix handles the dependency graph:

# configuration.nix
{ config, pkgs, ... }:
{
  # Enable NVIDIA driver
  hardware.nvidia = {
    modesetting.enable = true;
    open = false;  # Use proprietary driver for DGX
    nvidiaSettings = true;
  };
 
  # NVIDIA container toolkit (if using containers)
  hardware.nvidia-container-toolkit.enable = true;
 
  # Ensure the kernel module loads
  services.xserver.videoDrivers = [ "nvidia" ];
}

For the CUDA toolkit, I prefer managing it at the project level through Nix flakes rather than system-wide. This way, different projects can pin different CUDA versions without conflicts.

Flakes: Where It Gets Good

Nix flakes are the modern way to manage Nix projects. They give you a flake.lock file that pins every dependency to an exact revision, making builds fully reproducible across machines and across time.

Here's a flake I've used as a starting point for ML projects on the Spark:

# flake.nix
{
  description = "ML development environment for DGX Spark";
 
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
  };
 
  outputs = { self, nixpkgs }:
  let
    system = "aarch64-linux";
    pkgs = import nixpkgs {
      inherit system;
      config.allowUnfree = true;  # Required for CUDA
    };
  in {
    devShells.${system}.default = pkgs.mkShell {
      buildInputs = with pkgs; [
        python311
        python311Packages.torch
        python311Packages.transformers
        cudatoolkit
        cudnn
        git
        tmux
        htop
      ];
 
      shellHook = ''
        export CUDA_PATH=${pkgs.cudatoolkit}
        export LD_LIBRARY_PATH=${pkgs.lib.makeLibraryPath [
          pkgs.cudatoolkit
          pkgs.cudnn
        ]}:$LD_LIBRARY_PATH
      '';
    };
  };
}

Drop into this environment with nix develop, and you get a shell where PyTorch, CUDA, and cuDNN are all present at compatible versions. Share the flake with a teammate. They run nix develop on their machine (even if it's not a Spark), and they get the same environment. No setup scripts. No "install CUDA 12.4, then cuDNN 8.9.7, then set these three environment variables" README files that go stale.

The flake.lock captures every input revision. Check it into git. Now your environment is versioned alongside your model code.

Managing the Full System with Flakes

You can manage the entire NixOS system with flakes too, not just project environments. This is the approach I prefer for the Spark:

# flake.nix (system-level, simplified)
{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
  };
 
  outputs = { self, nixpkgs }: {
    nixosConfigurations.spark = nixpkgs.lib.nixosSystem {
      system = "aarch64-linux";
      modules = [
        ./hardware-configuration.nix
        ./nvidia.nix
        ./networking.nix
        ./users.nix
      ];
    };
  };
}

Split your config into modules. One for hardware, one for NVIDIA, one for networking, one for user accounts. Each is small, readable, and independently testable. Rebuild with nixos-rebuild switch -flake .#spark.

Now imagine this: you buy a second Spark six months from now. Clone the repo, run the rebuild. Same system. Identical. Not "mostly the same" or "same except for that one thing Dave changed." Actually identical.

The "Works on My Machine" Problem, Solved

I've watched ML teams lose weeks to environment drift. A new researcher joins, spends two days setting up their workstation, and their training runs produce slightly different results because cuDNN was a patch version behind. Or worse, the same code runs fine on one machine and crashes on another with an opaque CUDA error.

NixOS doesn't just mitigate this. It eliminates it at the root. When your OS configuration is a set of versioned, declarative files, and your development environments are pinned via flake locks, there's no space for drift to creep in.

The DGX Spark makes this practical because it's a single, consistent hardware target. You're not dealing with the combinatorial explosion of "any GPU from the last 5 years." You know the exact hardware. Your NixOS config can be tuned specifically for it.

Caveats and Honest Gotchas

Nothing's perfect. A few things to watch out for:

NixOS on aarch64. The Spark runs an ARM-based Grace CPU. Most NixOS packages build fine on aarch64-linux, but you'll occasionally hit a package that doesn't. Check hydra.nixos.org for build status before assuming something will work.

CUDA on NixOS isn't zero-friction. It's better than it was two years ago, but you'll still run into situations where a Python package's CUDA bindings don't play nice with Nix's library paths. The shellHook workaround with LD_LIBRARY_PATH is ugly, but it works. The NixOS CUDA ecosystem is improving fast.

Learning curve. Nix the language is functional and somewhat alien if you've never touched Haskell or a Lisp. The first week is rough. After that, you start seeing the design decisions behind it and it clicks.

Proprietary NVIDIA drivers update cadence. NVIDIA pushes driver updates on their own schedule. NixOS packages them, but there's occasionally a lag. Pin your driver version if you need stability.

Getting Started

If you want to try this, here's a practical path:

  1. Install NixOS from the latest unstable ISO on the DGX Spark.
  2. Start with the basic NVIDIA driver config shown above.
  3. Create a flake for your ML project with the CUDA/PyTorch stack you need.
  4. Run nix develop to enter your environment.
  5. Iterate on your system config as you discover what you need.
  6. Push everything to a private repo.

Within a day, you'll have a fully reproducible AI workstation. Within a week, you'll wonder how you ever managed ML infrastructure without declarative configuration.

The DGX Spark is good hardware. Pairing it with NixOS makes it predictable infrastructure. And predictability is what separates a workstation you can depend on from one that's one apt upgrade away from breaking your training pipeline.

DR

Dian Rijal Asyrof

Writes about useful AI tools, programming practice, and the craft of building reliable software.

Previous articleGoogle Killed Its Earth AI Feature After Just One Day, Here's What HappenedNext articleDevelopers Don't Pick the Best Tool, They Pick the One They Trust
NixosNvidiaAI InfrastructureReproducibilityLinux
On this page↓
  1. What the DGX Spark Actually Is
  2. NixOS in 60 Seconds
  3. DGX Spark + NixOS: The Hardware Setup
  4. NVIDIA Drivers and CUDA: The Part Everyone Worries About
  5. Flakes: Where It Gets Good
  6. Managing the Full System with Flakes
  7. The "Works on My Machine" Problem, Solved
  8. Caveats and Honest Gotchas
  9. Getting Started

On this page

  1. What the DGX Spark Actually Is
  2. NixOS in 60 Seconds
  3. DGX Spark + NixOS: The Hardware Setup
  4. NVIDIA Drivers and CUDA: The Part Everyone Worries About
  5. Flakes: Where It Gets Good
  6. Managing the Full System with Flakes
  7. The "Works on My Machine" Problem, Solved
  8. Caveats and Honest Gotchas
  9. Getting Started

See also

Illustration for Debugging RipGrep: Why Musl Binaries Segfault on Large Directory Searches
Programming/Aug 3, 2026

Debugging RipGrep: Why Musl Binaries Segfault on Large Directory Searches

A deep dive into why RipGrep musl-compiled static binaries are experiencing segfaults on exceptionally large directory scans and how to work around it.

5 min read
Developer ToolsRust
Illustration for Why Bashumerate Was Built: Replacing Xargs with Safe, Readable Pipeline Automation
Programming/Jul 21, 2026

Why Bashumerate Was Built: Replacing Xargs with Safe, Readable Pipeline Automation

An technical inspection of xargs edge cases, null-byte delimiter failures, and how bashumerate provides a safer, more readable enumerator for complex shell pipelines.

3 min read
LinuxBash
Illustration for Podman v6.0.0 Drops: The Networking Stack Overhaul That Actually Matters
Programming/Jul 3, 2026

Podman v6.0.0 Drops: The Networking Stack Overhaul That Actually Matters

Podman v6.0.0 ships a full networking stack rebuild, replacing slirp4netns and iptables with Netavark, Pasta, and nftables. Here is what breaks, what improves, and what you need to update.

3 min read
PodmanContainers