nova-nix: Windows-native Nix implementation in Haskell and C99

[ apache, distribution, library, nix, program, system ] [ Propose Tags ] [ Report a vulnerability ]

An implementation of Nix for Windows, written in Haskell with a C99 data layer that keeps evaluation data off the GHC heap. It also runs on macOS and Linux. It has its own parser, lazy evaluator, content-addressed store, derivation builder and binary-cache substituter, and does not need an existing Nix installation.

On the pinned nixpkgs revision its CI checks, the derivation paths it computes match upstream Nix 2.24.9. On Windows it builds packages from source through a stage-1 stdenv over a store-pinned MinGW-w64 toolchain. The project is experimental; see the README for what is not implemented yet.

Evaluation needs the C data layer, so library code must run it between Nix.Eval.Arena.arenaInit and Nix.Eval.Arena.arenaDestroy.

Built on nova-cache for NAR serialization, narinfo handling, and Ed25519-signed binary substitution.


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.1.0.0, 0.1.0.1, 0.1.1.0, 0.1.2.0, 0.1.3.0, 0.1.4.0, 0.1.5.0, 0.1.6.0, 0.1.7.0, 0.1.7.1, 0.1.8.0, 0.1.9.0, 0.2.0.0, 0.3.0.0, 0.4.0.0, 0.5.0.0, 0.6.0.0, 0.8.0.0
Change log CHANGELOG.md
Dependencies array (>=0.5 && <0.6), base (>=4.22 && <5), bytestring (>=0.11 && <0.13), containers (>=0.6 && <0.9), crypton (>=1.1 && <2), directory (>=1.3 && <1.4), filelock (>=0.1.1 && <0.2), filepath (>=1.4 && <1.6), http-client (>=0.7 && <0.8), http-client-tls (>=0.3 && <0.5), http-types (>=0.12 && <0.13), mtl (>=2.2 && <2.4), nova-cache (>=0.11.1.1 && <0.12), nova-nix, process (>=1.6 && <1.7), ram (>=0.20 && <1), regex-tdfa (>=1.3 && <1.4), sqlite-simple (>=0.4 && <0.5), tar (>=0.7.1 && <0.8), text (>=2.0 && <2.2), time (>=1.9 && <1.17), zstd (>=0.1 && <0.2) [details]
Tested with ghc ==9.14.1
License Apache-2.0
Copyright 2026 Novavero AI Inc.
Author Devon Tomlin
Maintainer devon.tomlin@novavero.ai
Uploaded by aoinoikaz at 2026-10-08T22:41:59Z
Category Nix, Distribution, System
Home page https://github.com/Novavero-AI/nova-nix
Bug tracker https://github.com/Novavero-AI/nova-nix/issues
Source repo head: git clone https://github.com/Novavero-AI/nova-nix -b main
Distributions
Executables nova-nix
Downloads 317 total (44 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user [build log]
All reported builds failed as of 2026-10-08 [all 2 reports]

Readme for nova-nix-0.8.0.0

[back to package description]

nova-nix

CI Hackage License

nova-nix is an implementation of Nix for Windows, written in Haskell with a C99 data layer. It also builds and runs on macOS and Linux. It has its own parser, evaluator, store, builder and binary-cache substituter, and does not need an existing Nix installation.

nova-nix is experimental. Read Limitations before relying on it.

Status

  • Evaluation matches upstream Nix on the cases CI checks. On a pinned nixpkgs 24.11 revision, hello.drvPath and a dependent derivation evaluate to the same store paths as Nix 2.24.9, and 23 smaller evaluation cases produce the same output. CI runs this comparison on every change. A matching drvPath means the whole build-time closure behind it matches too. How much of the rest of nixpkgs evaluates has not been measured yet (#29).
  • Windows builds run natively. CI builds GNU Hello on a Windows runner through a stage-1 stdenv. Its toolchain is 17 MinGW-w64 packages and 22 MSYS2 packages, each fetched as a fixed-output derivation pinned by SHA-256 and unpacked into the store. sed, zlib and a small library-linking example also have recipes, but CI does not build them. Replacing these binary seeds with a toolchain built from source is tracked in #26.
  • Binary caches work in both directions. nova-nix push uploads a closure, and build --substituter downloads signed NARs instead of building. CI checks the round trip on Linux against a local nova-cache server.

Limitations

  • No flakes, no nix-shell or nix develop, and no daemon or multi-user mode.
  • No garbage collection yet (#24). nova-nix store delete removes individual paths.
  • On Windows a build's process tree runs in a job object, so stopping a build stops everything it started. There is no filesystem or network isolation yet (#25).
  • nova-nix itself needs neither WSL nor Cygwin, but the current Windows stdenv runs its build scripts with MSYS2's bash.
  • Store paths that contain symlinks need Windows Developer Mode or an elevated shell. nova-nix creates native symlinks and fails rather than falling back to a copy.

Install

Each release has an archive per platform:

Platform Archive
Linux x86_64 nova-nix-linux-x64.tar.gz
macOS arm64 nova-nix-macos-arm64.tar.gz
Windows x86_64 nova-nix-windows-x64.zip

Each archive unpacks to a single directory holding bin/, share/nova-nix/ and pkgs/. share/nova-nix/ provides the <nix/*> search path, so the binary works wherever the directory is unpacked, and pkgs/ holds the package recipes. Check the download against the SHA256SUMS file attached to the same release.

In a GitHub Actions workflow:

- uses: Novavero-AI/install-nova-nix@v1
- run: nova-nix eval --expr '1 + 2'

Usage

$ nova-nix eval --expr '1 + 2'
3
$ nova-nix eval --strict --expr 'builtins.map (x: x * x) [ 1 2 3 4 5 ]'
[ 1 4 9 16 25 ]
$ nova-nix eval FILE.nix                          # evaluate a file
$ nova-nix build FILE.nix -A ATTR                 # build an attribute of it
$ nova-nix build FILE.nix --substituter URL --trusted-key KEY  # try a cache first
$ nova-nix push --cache URL --key-file KEY --all  # upload the store to a cache
$ nova-nix --help

Evaluating a package from nixpkgs, on the 24.11 revision CI pins:

$ NIX_PATH=nixpkgs=/path/to/nixpkgs nova-nix eval --expr \
    '(import <nixpkgs> { system = "x86_64-linux"; config = {}; overlays = []; }).hello.drvPath'
"/nix/store/gciipqhqkdlqqn803zd4a389v86ran45-hello-2.12.1.drv"

Building GNU Hello on Windows, from the unpacked release directory:

> bin\nova-nix build pkgs\windows\hello.nix
...
C:\nix\store\<hash>-hello
> C:\nix\store\<hash>-hello\bin\hello.exe
Hello, world!

The first build fetches 40 pinned archives (the 39 toolchain packages and the Hello source), then builds the MSYS2 seed, the MinGW-w64 seed and Hello.

How it works

  • Parser (Nix.Parser): a hand-written recursive-descent parser for the Nix 2.24 language.
  • Evaluator (Nix.Eval): the AST compiles to a small bytecode that a lazy evaluator runs, memoizing thunks and detecting infinite recursion. The evaluator is generic over MonadEval, with a pure instance for tests and an IO instance for real evaluation. derivation is a lazy wrapper over the strict derivationStrict primop, as in upstream's src/libexpr/primops/derivation.nix, so referring to a package does not force its build closure.
  • Data layer (cbits/): attribute sets, lists, thunks, environments, symbols, context strings, lambdas and bytecode are C99 structures outside the GHC heap, freed together when an evaluation session ends. Haskell calls into C, and C never calls back.
  • Store (Nix.Store): a content-addressed store at /nix/store, or C:\nix\store on Windows, with SQLite metadata, reference scanning and per-path locks that follow upstream's protocol.
  • Builder (Nix.Builder): orders derivations by their dependencies, tries substitution first, and runs each builder in a scrubbed environment.
  • Substituter (Nix.Substituter): the HTTP binary-cache protocol, with Ed25519 signature checks and xz, zstd and bzip2 decompression, built on nova-cache.

On Windows, derivations keep the canonical /nix/store spelling that hashes are computed over, and it is mapped to the real store directory only when a builder is started. NTFS has no executable bit, so nova-nix keeps it in an alternate data stream. A store path therefore serializes to the same NAR, with the same hash, as it does on other platforms.

Library

{-# LANGUAGE OverloadedStrings #-}

import Control.Exception (bracket_)
import Nix.Builtins (builtinEnv)
import Nix.Eval (eval, runPureEval)
import Nix.Eval.Arena (arenaDestroy, arenaInit)
import Nix.Parser (parseNix)

main :: IO ()
main = bracket_ arenaInit arenaDestroy $
  -- The first argument is what relative path literals resolve against.
  case parseNix "/tmp" "<expr>" "let x = 5; in x * 2 + 1" of
    Left err -> print err
    Right expr -> print (runPureEval (eval (builtinEnv 0 []) expr))

This prints Right (VInt 11). Evaluation needs the C data layer, so it must run between arenaInit and arenaDestroy.

Building from source

Tested with GHC 9.14.1. CI uses the latest cabal-install release. You only need this to work on nova-nix itself, not to use a release.

git clone https://github.com/Novavero-AI/nova-nix.git
cd nova-nix
cabal update
cabal build
cabal test

Contributing

See CONTRIBUTING.md. Planned work is on the Nova roadmap project. Please report security issues privately through GitHub's vulnerability reporting rather than in a public issue.

License

Apache-2.0. See LICENSE and NOTICE.