- Nix 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Keeping the Node.js and package manager versions in package.json, .node-version and Nix in sync by hand drifts. Deriving the Nix packages from the files the JavaScript tooling already reads makes package.json the single source of truth. Package managers are fetched at exactly the pinned version rather than mapped to the nearest nixpkgs release, because pnpm and Corepack download the pinned release themselves whenever the version on PATH differs, defeating the pin. The +sha512.<hex> suffix written by `corepack use` is the digest of the same artifact Corepack downloads, so it doubles as the fetch hash; specs without a hash Nix can verify require an explicit one instead of falling back. Node.js does not self-update, so a nixpkgs nodejs_<major> is the default and a patch mismatch only warns; per-system hashes opt into the official binary for an exact match. The overlay adds pkgs.nodeToolchain instead of overriding nodejs or pnpm, which would rebuild their nixpkgs dependents and shift pnpm dependency hashes. Assisted-by: Claude Code:Opus 5.5 |
||
| lib | ||
| pkgs | ||
| tests | ||
| flake.lock | ||
| flake.nix | ||
| README.md | ||
node-toolchain.nix
Builds Node.js and the package manager pinned in package.json#packageManager with Nix,
so the versions live in one place and nothing downloads them at run time.
Mismatched versions cannot fall back to whatever nixpkgs ships: pnpm (>= 9.7) and Corepack
read packageManager and fetch the pinned release themselves when the version on PATH
differs, so every artifact is fetched at the exact pinned version and verified by hash.
Usage
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
node-toolchain.url = "github:natsukium/node-toolchain.nix";
};
outputs =
{ nixpkgs, node-toolchain, ... }:
let
system = "aarch64-darwin";
pkgs = import nixpkgs {
inherit system;
overlays = [ (node-toolchain.lib.mkOverlay { src = ./.; }) ];
};
in
{
devShells.${system}.default = pkgs.mkShell {
packages = pkgs.nodeToolchain.packages;
};
};
}
pkgs.nodeToolchain provides:
| Attribute | Value |
|---|---|
nodejs |
Node.js |
packageManager |
the pinned package manager, or null |
pnpm / yarn / npm |
the same package manager under its own name |
packages |
[ packageManager nodejs ], ready for mkShell |
The overlay adds nodeToolchain instead of replacing nodejs or pnpm, which would rebuild
or change the dependency hashes of every nixpkgs package that uses them.
lib.mkToolchain { pkgs; src; ... } returns the same set without an overlay.
The pnpm derivation has nodejs-slim and version, so it can be passed to fetchPnpmDeps.
Package manager
packageManager |
Fetched from |
|---|---|
pnpm@<12 |
registry.npmjs.org/pnpm, run with Node.js |
pnpm@>=12 |
the wrapper above plus the native @pnpm/exe.* |
yarn@1 |
registry.yarnpkg.com/yarn |
yarn@>=2 |
repo.yarnpkg.com/<version>/.../yarn.js |
npm |
registry.npmjs.org/npm |
These are the artifacts Corepack downloads, so the +sha512.<hex> suffix that
corepack use writes is used as the hash directly. Without it (or with an algorithm Nix
cannot verify, such as sha224), pass the hash yourself:
mkOverlay {
src = ./.;
hashes.packageManager = "sha512-...";
}
pnpm 12 and later is a native executable that its npm wrapper downloads on first run, so it
also needs one hash per system, the dist.integrity of @pnpm/exe.<target>
(darwin-arm64, linux-arm64-musl, linux-x64-musl):
hashes.pnpmExe = {
aarch64-darwin = "sha512-...";
x86_64-linux = "sha512-...";
};
Node.js
The version is read from the first of these that exists:
package.json#devEngines.runtime(name = "node").node-version.nvmrcpackage.json#volta.node
Only plain versions (22, 22.1, v22.1.0) are accepted. Pass nodeVersion to override.
With none of them, pkgs.nodejs is used.
By default the version selects nodejs_<major> from nixpkgs, with a warning when its
minor or patch version differs from the requested one. To match the version exactly,
pass the sha256 of the official binary tarball for each system, as listed in
https://nodejs.org/dist/v<version>/SHASUMS256.txt:
hashes.nodejs = {
aarch64-darwin = "sha256-...";
x86_64-linux = "sha256-...";
};