Skip to content

Nix Integration

cuenv integrates with Nix to provide reproducible development environments. When you have a flake.nix in your project, cuenv can automatically load the Nix development environment alongside your CUE configuration.

The Nix integration allows you to:

  • Automatically load Nix flake development environments
  • Combine Nix-provided tools with cuenv’s typed environment variables
  • Ensure reproducible builds across different machines
  • Share consistent development environments with your team

If you don’t have Nix installed:

Terminal window
# Official installer (multi-user)
sh <(curl -L https://nixos.org/nix/install) --daemon
# Or use the Determinate Systems installer (recommended)
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh

Add to ~/.config/nix/nix.conf or /etc/nix/nix.conf:

experimental-features = nix-command flakes

A typical project with Nix integration:

my-project/
├── env.cue # cuenv configuration
├── flake.nix # Nix flake definition
├── flake.lock # Locked dependencies
└── src/
{
description = "My project development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in {
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
nodejs_20
pnpm
postgresql
redis
];
shellHook = ''
echo "Development environment loaded"
'';
};
}
);
}
package cuenv
import "github.com/cuenv/cuenv/schema"
schema.#Cuenv
env: {
NODE_ENV: "development"
DATABASE_URL: "postgresql://localhost/myapp_dev"
}
hooks: {
onEnter: {
// Load Nix flake environment
nix: schema.#NixFlake
}
}
tasks: {
dev: {
command: "pnpm"
args: ["run", "dev"]
}
}

cuenv provides a built-in #NixFlake hook type that loads your Nix development environment:

import "github.com/cuenv/cuenv/schema"
hooks: {
onEnter: {
nix: schema.#NixFlake
}
}

The #NixFlake hook:

  1. Detects flake.nix and flake.lock in your project
  2. Runs nix print-dev-env to get the environment
  3. Sources the environment variables into your shell
  4. Tracks flake.nix and flake.lock as inputs for cache invalidation
#NixFlake: #ExecHook & {
order: 10 // Run early in hook sequence
propagate: true // Export to child processes
command: "nix"
args: ["print-dev-env"]
source: true // Source output as shell script
inputs: ["flake.nix", "flake.lock"]
}

Combine Nix-provided tools with cuenv’s typed environment:

package cuenv
import "github.com/cuenv/cuenv/schema"
schema.#Cuenv
// Environment variables (typed by CUE)
env: {
// App configuration
NODE_ENV: "development" | "production"
PORT: 3000
// Database (Nix provides the postgres binary)
PGHOST: "localhost"
PGPORT: "5432"
PGDATABASE: "myapp_dev"
}
hooks: {
onEnter: {
// Nix provides: bun, psql, redis-cli, etc.
nix: schema.#NixFlake
}
}
tasks: {
// These commands come from Nix
dev: {command: "pnpm", args: ["run", "dev"]}
build: {command: "pnpm", args: ["run", "build"]}
db: {
migrate: {command: "psql", args: ["-f", "migrations/up.sql"]}
reset: {command: "psql", args: ["-f", "migrations/reset.sql"]}
}
}

Use different Nix outputs for different scenarios:

flake.nix
{
outputs = { self, nixpkgs, ... }:
# ...
{
devShells = {
default = pkgs.mkShell {
buildInputs = with pkgs; [ bun ];
};
ci = pkgs.mkShell {
buildInputs = with pkgs; [ bun chromium ];
};
production = pkgs.mkShell {
buildInputs = with pkgs; [ bun ];
};
};
};
}

cuenv works alongside direnv. If you’re already using direnv with Nix:

.envrc:

Terminal window
use flake

You can still use cuenv for additional typed configuration:

package cuenv
import "github.com/cuenv/cuenv/schema"
schema.#Cuenv
// Don't load Nix via cuenv if direnv handles it
env: {
APP_NAME: "my-app"
LOG_LEVEL: "debug"
}
tasks: {
dev: {command: "bun", args: ["run", "dev"]}
}
error: hook failed: command 'nix' not found

Fix: Ensure Nix is installed and in your PATH:

Terminal window
# Check Nix installation
nix --version
# If using nix-daemon, ensure it's running
sudo systemctl status nix-daemon
error: hook failed: 'flake.nix' not found in current directory

Fix: Ensure you’re in a directory with a flake.nix file, or create one:

Terminal window
nix flake init

Nix evaluation can be slow on first run. Tips:

  1. Use binary caches in flake.nix:

    nixConfig = {
    extra-substituters = ["https://cache.nixos.org"];
    };
  2. Enable the nix-daemon for better caching

  3. Use cachix for custom binary caches:

    Terminal window
    cachix use my-cache
error: lock file needs to be updated

Fix: Update your lock file:

Terminal window
nix flake update

Always commit flake.lock for reproducibility:

Terminal window
git add flake.lock
git commit -m "chore: update nix flake lock"
  • Use Nix for tooling (compilers, formatters, databases)
  • Use cuenv for configuration (environment variables, secrets, tasks)

List Nix-provided tools in your README:

## Development Setup
This project uses Nix for tooling. Enter the development shell:
\`\`\`bash
nix develop
# Or with cuenv (loads automatically)
cd project-dir
\`\`\`
**Provided tools:**
- Bun
- PostgreSQL 16
- Redis 7

Use Nix in CI for reproducible builds:

.github/workflows/ci.yml
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v25
with:
extra_nix_config: |
experimental-features = nix-command flakes
- run: nix develop --command cuenv task ci