smithery/olafkfreund

node2nix

node2nix Skill

Installation

$ npx skills add smithery/olafkfreund --skill node2nix

Also in this package

Other skills from smithery/olafkfreund · top by installs.

npx skills add smithery/olafkfreund

Browse all from smithery/olafkfreund

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Version1

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 23,475 B
  • docs SUMMARY.md 30 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

node2nix Skill

A specialized skill for converting NPM packages to Nix expressions using node2nix, enabling declarative and reproducible Node.js package management with Nix.

Skill Overview

Purpose: Provide comprehensive support for using node2nix to generate Nix expressions from NPM packages, handle dependencies, and integrate Node.js projects with Nix/NixOS.

Invoke When:

  • Converting npm projects to Nix packages
  • Creating Nix derivations for Node.js applications
  • Packaging Node.js tools for NixOS
  • Managing Node.js dependencies declaratively
  • Building reproducible Node.js applications
  • Troubleshooting node2nix issues
  • Setting up development environments for Node.js

Core Capabilities

1. Installation

Via Nix (Recommended)

# Install node2nix from nixpkgs
nix-env -f '<nixpkgs>' -iA nodePackages.node2nix

# Or with nix profile
nix profile install nixpkgs#nodePackages.node2nix

# Verify installation
node2nix --version

On NixOS

# /etc/nixos/configuration.nix
environment.systemPackages = with pkgs; [
  nodePackages.node2nix
];

Via home-manager

# home.nix
home.packages = with pkgs; [
  nodePackages.node2nix
];

Via npm (Alternative)

# Global installation
npm install -g node2nix

# Or use npx (no installation)
npx node2nix

2. Basic Usage

Quick Start - Generate from package.json

# Navigate to your Node.js project
cd my-nodejs-project

# Generate Nix expressions
node2nix

# This creates three files:
# - node-packages.nix (package definitions)
# - node-env.nix (build logic)
# - default.nix (composition expression)

Build the Package

# Build the package
nix-build -A package

# Result symlink points to build output
./result/bin/my-app

# Or install to profile
nix-env -f default.nix -iA package

Generated Files Explained

default.nix - Main entry point:

{ pkgs ? import <nixpkgs> {} }:

let
  nodePackages = import ./node-packages.nix {
    inherit pkgs;
    inherit (pkgs) system fetchurl fetchgit stdenv lib;
  };
in
{
  package = nodePackages.package;
  shell = nodePackages.shell;
}

node-packages.nix - Package definitions:

# Generated by node2nix
# Contains all package definitions with dependencies
{
  # ... dependency definitions
  "my-package" = nodeEnv.buildNodePackage {
    name = "my-package";
    version = "1.0.0";
    src = ./.;
    dependencies = [ ... ];
    # ... build configuration
  };
}

node-env.nix - Build environment:

# Shared build logic for all packages
# Handles npm install, dependency linking, etc.
# Usually not modified directly

3. Lock File Support

Using package-lock.json (npm 5+)

# Generate with package-lock.json
node2nix -l package-lock.json

# Or explicitly
node2nix --lock package-lock.json

# Ensures exact dependency versions

Using npm-shrinkwrap.json

# Generate with shrinkwrap file
node2nix -l npm-shrinkwrap.json

Using yarn.lock

# Generate with yarn lock file
node2nix -l yarn.lock

# Note: Requires yarn support in node2nix

Why Use Lock Files?

  • Reproducibility: Exact same packages every time
  • Version Pinning: Lock specific dependency versions
  • Security: Prevent unexpected updates
  • Consistency: Same builds across machines

4. Development vs Production Dependencies

Production Mode (Default)

# Only install production dependencies
node2nix

# Explicit production mode
node2nix --production

Development Mode

# Include devDependencies
node2nix --development

# Useful for building developer tools
node2nix --development -i package.json

Example: Building a Tool with Dev Dependencies

# For tools like TypeScript compiler
node2nix --development

# Result includes devDependencies
nix-build -A package

5. Node.js Version Targeting

Default (Node.js 12+)

# Uses latest LTS Node.js
node2nix

Node.js 4.x Compatibility

# Enable Node.js 4.x mode
node2nix -4

# Equivalent to:
node2nix --nodejs-4

Node.js 6.x

node2nix -6

Node.js 8.x

node2nix -8

Custom Node.js Version in Generated Package

# Override Node.js version in default.nix
{ pkgs ? import <nixpkgs> {} }:

let
  nodejs = pkgs.nodejs_20;  # Use Node.js 20
  nodePackages = import ./node-packages.nix {
    inherit pkgs;
    inherit (pkgs) system fetchurl fetchgit stdenv lib;
    nodejs = nodejs;
  };
in
{
  package = nodePackages.package;
}

6. Input Files

Custom Input File

# Use custom package.json location
node2nix -i packages/backend/package.json

# Output to custom directory
node2nix -i package.json -o node-packages.nix

# Custom composition file
node2nix -c my-composition.nix

Multiple Packages

# Create a node-packages.json file
cat > node-packages.json <<EOF
[
  "express",
  "lodash",
  "axios"
]
EOF

# Generate from package list
node2nix -i node-packages.json

# Builds packages without package.json

Supplement File

# Add extra packages not in dependencies
cat > supplement.json <<EOF
{
  "global-tools": {
    "pm2": "^5.0.0",
    "nodemon": "^2.0.0"
  }
}
EOF

# Generate with supplements
node2nix --supplement-input supplement.json

7. Private Registries & Authentication

Private Registry

# Configure private registry
node2nix \
  --registry "https://registry.company.com" \
  --registry-auth-token "YOUR_AUTH_TOKEN"

# With scope
node2nix \
  --registry "https://registry.company.com" \
  --registry-scope "@mycompany"

Multiple Registries

# Different registries for different scopes
node2nix \
  --registry "https://public.npm.org" \
  --registry "https://private.company.com" \
  --registry-scope "@company" \
  --registry-auth-token "TOKEN"

Using .npmrc

# node2nix respects .npmrc settings
cat > .npmrc <<EOF
@mycompany:registry=https://registry.company.com/
//registry.company.com/:_authToken=YOUR_TOKEN
EOF

node2nix

Private Git Repositories

# Enable SSH for private git deps
node2nix --use-fetchgit-private

# For dependencies like:
# "my-lib": "git+ssh://[email protected]/company/lib.git"

8. Dependency Handling

Peer Dependencies

# Include peer dependencies
node2nix --include-peer-dependencies

# Useful for plugin systems

Strip Optional Dependencies

# Remove optional dependencies
node2nix --strip-optional-dependencies

# Helps when optional deps cause build failures

Bypass Cache

# Force fresh package metadata fetch
node2nix --bypass-cache

# Useful when registry data is stale

No Copy DevDependencies

# Don't copy devDependencies to store
node2nix --no-copy-node-env

# Reduces closure size

9. Override Mechanism

Basic Override

# default.nix
{ pkgs ? import <nixpkgs> {} }:

let
  nodePackages = import ./node-packages.nix {
    inherit pkgs;
    inherit (pkgs) system fetchurl fetchgit stdenv lib;
  };
in
{
  package = nodePackages.package.override {
    # Add native dependencies
    buildInputs = with pkgs; [
      python3
      pkgs.cairo
      pkgs.pango
    ];

    # Skip npm install phase
    dontNpmInstall = true;

    # Custom build phase
    buildPhase = ''
      npm run custom-build
    '';
  };
}

Override Specific Package

{ pkgs ? import <nixpkgs> {} }:

let
  nodePackages = (import ./node-packages.nix {
    inherit pkgs;
    inherit (pkgs) system fetchurl fetchgit stdenv lib;
  }).override {
    # Override for specific dependency
    "canvas" = oldAttrs: {
      buildInputs = oldAttrs.buildInputs ++ [
        pkgs.cairo
        pkgs.pango
        pkgs.giflib
      ];

      preInstall = ''
        export CANVAS_NO_REBUILD=1
      '';
    };

    # Fix bcrypt native module
    "bcrypt" = oldAttrs: {
      buildInputs = [ pkgs.python3 ];
    };
  };
in
{
  package = nodePackages.package;
}

Global Override

# Override all packages
{ pkgs ? import <nixpkgs> {} }:

let
  nodePackages = import ./node-packages.nix {
    inherit pkgs;
    inherit (pkgs) system fetchurl fetchgit stdenv lib;

    # Global overrides
    globalBuildInputs = with pkgs; [
      python3
      pkgs.nodejs.libv8
    ];
  };
in
nodePackages

10. Development Shell

Generate Shell Environment

# Generate with shell support
node2nix

# Enter development shell
nix-shell -A shell

# Now you can:
# - Modify source code
# - Run npm scripts
# - Test without rebuilding

Enhanced Shell

# shell.nix
{ pkgs ? import <nixpkgs> {} }:

let
  nodePackages = import ./node-packages.nix {
    inherit pkgs;
    inherit (pkgs) system fetchurl fetchgit stdenv lib;
  };
in
nodePackages.shell.override {
  buildInputs = with pkgs; [
    # Additional development tools
    nodejs_20
    nodePackages.typescript
    nodePackages.eslint
    nodePackages.prettier

    # Native dependencies for development
    python3
    cairo
    pango
  ];

  shellHook = ''
    echo "Node.js development environment"
    echo "Node version: $(node --version)"
    echo "npm version: $(npm --version)"

    # Set up node_modules symlink
    [ -d node_modules ] || ln -s $NODE_PATH node_modules

    # Custom environment variables
    export NODE_ENV=development
    export DEBUG=*
  '';
}

Using the Shell

# Enter shell
nix-shell

# Run development server
npm run dev

# Run tests
npm test

# Build
npm run build

11. Common Patterns

Pattern 1: Simple CLI Tool

# Project structure:
# my-cli/
# ├── package.json
# ├── package-lock.json
# └── bin/
#     └── my-cli.js

# Generate Nix expressions
cd my-cli
node2nix -l package-lock.json

# Build
nix-build -A package

# Test
./result/bin/my-cli --version

# Install
nix-env -f default.nix -iA package

Pattern 2: Web Application

# Express.js app with dependencies
node2nix -l package-lock.json

# Custom default.nix for systemd service
{ pkgs ? import <nixpkgs> {} }:

let
  nodePackages = import ./node-packages.nix {
    inherit pkgs;
    inherit (pkgs) system fetchurl fetchgit stdenv lib;
  };

  app = nodePackages.package;
in
{
  inherit app;

  # Systemd service
  service = pkgs.writeTextFile {
    name = "my-app.service";
    text = ''
      [Unit]
      Description=My Node.js App
      After=network.target

      [Service]
      Type=simple
      ExecStart=${app}/bin/my-app
      Restart=on-failure
      Environment="NODE_ENV=production"

      [Install]
      WantedBy=multi-user.target
    '';
  };
}

Pattern 3: Monorepo Package

# Workspace project
# monorepo/
# ├── package.json
# ├── packages/
# │   ├── app/
# │   │   └── package.json
# │   └── lib/
# │       └── package.json

# Generate from root
node2nix -l package-lock.json

# Or generate per package
cd packages/app
node2nix -l ../../package-lock.json

Pattern 4: TypeScript Project

# Include dev dependencies for TypeScript
node2nix --development -l package-lock.json

# Build includes TypeScript compilation
{ pkgs ? import <nixpkgs> {} }:

let
  nodePackages = import ./node-packages.nix {
    inherit pkgs;
    inherit (pkgs) system fetchurl fetchgit stdenv lib;
  };
in
{
  package = nodePackages.package.override {
    buildPhase = ''
      # Compile TypeScript
      npm run build
    '';

    installPhase = ''
      mkdir -p $out/bin
      cp -r dist/* $out/

      # Create wrapper
      makeWrapper ${pkgs.nodejs}/bin/node $out/bin/my-app \
        --add-flags "$out/index.js"
    '';
  };
}

Pattern 5: Electron App

# Electron requires development dependencies
node2nix --development -l package-lock.json
{ pkgs ? import <nixpkgs> {} }:

let
  nodePackages = import ./node-packages.nix {
    inherit pkgs;
    inherit (pkgs) system fetchurl fetchgit stdenv lib;
  };
in
{
  package = nodePackages.package.override {
    buildInputs = with pkgs; [
      # Electron dependencies
      xorg.libX11
      xorg.libXtst
      gtk3
      nss
      nspr
      alsa-lib
      cups
      dbus
      atk
      cairo
      pango
      gdk-pixbuf
      gtk3
    ];

    # Don't rebuild native modules
    ELECTRON_SKIP_BINARY_DOWNLOAD = "1";
  };
}

12. NixOS Integration

Package in NixOS Configuration

# /etc/nixos/configuration.nix
{ config, pkgs, ... }:

let
  myNodeApp = import /path/to/my-app {
    inherit pkgs;
  };
in
{
  environment.systemPackages = [
    myNodeApp.package
  ];

  # Or as a systemd service
  systemd.services.my-node-app = {
    description = "My Node.js Application";
    after = [ "network.target" ];
    wantedBy = [ "multi-user.target" ];

    serviceConfig = {
      ExecStart = "${myNodeApp.package}/bin/my-app";
      Restart = "on-failure";
      User = "nodejs";

      # Security hardening
      DynamicUser = true;
      ProtectSystem = "strict";
      NoNewPrivileges = true;
      PrivateTmp = true;
    };

    environment = {
      NODE_ENV = "production";
      PORT = "3000";
    };
  };
}

Module for Node.js App

# modules/my-app.nix
{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.services.my-app;

  myApp = import ../my-app {
    inherit pkgs;
  };
in
{
  options.services.my-app = {
    enable = mkEnableOption "My Node.js App";

    port = mkOption {
      type = types.int;
      default = 3000;
      description = "Port to listen on";
    };

    environment = mkOption {
      type = types.attrsOf types.str;
      default = {};
      description = "Environment variables";
    };
  };

  config = mkIf cfg.enable {
    systemd.services.my-app = {
      description = "My Node.js Application";
      after = [ "network.target" ];
      wantedBy = [ "multi-user.target" ];

      serviceConfig = {
        ExecStart = "${myApp.package}/bin/my-app";
        Restart = "on-failure";
        DynamicUser = true;
      };

      environment = cfg.environment // {
        NODE_ENV = "production";
        PORT = toString cfg.port;
      };
    };

    networking.firewall.allowedTCPPorts = [ cfg.port ];
  };
}

13. Flake Integration

flake.nix for Node.js Project

{
  description = "My Node.js Application";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};

        nodePackages = import ./node-packages.nix {
          inherit pkgs;
          inherit (pkgs) system fetchurl fetchgit stdenv lib;
        };
      in
      {
        packages = {
          default = nodePackages.package;
          my-app = nodePackages.package;
        };

        apps.default = {
          type = "app";
          program = "${nodePackages.package}/bin/my-app";
        };

        devShells.default = nodePackages.shell.override {
          buildInputs = with pkgs; [
            nodejs_20
            nodePackages.typescript
          ];
        };
      }
    );
}

Use Flake

# Build
nix build

# Run
nix run

# Development shell
nix develop

# Update dependencies
node2nix -l package-lock.json
nix flake lock --update-input nixpkgs

14. Troubleshooting

Issue 1: Native Module Build Failures

Problem: Package with native dependencies fails to build

Solution:

{ pkgs ? import <nixpkgs> {} }:

let
  nodePackages = import ./node-packages.nix {
    inherit pkgs;
    inherit (pkgs) system fetchurl fetchgit stdenv lib;
  };
in
{
  package = nodePackages.package.override {
    buildInputs = with pkgs; [
      python3  # For node-gyp
      pkgs.nodejs.libv8

      # Common native deps
      cairo
      pango
      giflib
      libjpeg
      libpng
    ];

    # Environment for native builds
    NIX_CFLAGS_COMPILE = "-I${pkgs.cairo.dev}/include/cairo";
    NIX_LDFLAGS = "-L${pkgs.cairo}/lib";
  };
}

Issue 2: Plugin Discovery Failures

Problem: Application can't find plugins/modules

Solution:

# In development shell
nix-shell -A shell

# Create node_modules symlink
ln -s $NODE_PATH node_modules

# Or in shell.nix:
shellHook = ''
  [ -d node_modules ] || ln -s $NODE_PATH node_modules
'';

Issue 3: Package Not Found in Registry

Problem: node2nix can't fetch package

Solution:

# Bypass cache
node2nix --bypass-cache

# Or update lock file
npm install
npm update
node2nix -l package-lock.json

Issue 4: Peer Dependency Issues

Problem: Missing peer dependencies

Solution:

# Include peer dependencies
node2nix --include-peer-dependencies -l package-lock.json

Issue 5: Private Git Repository Access

Problem: Can't fetch from private git repos

Solution:

# Enable SSH for git
node2nix --use-fetchgit-private

# Ensure SSH keys are configured
# For declarative builds, use fetchgit with SSH URL override

Issue 6: Large Closure Size

Problem: Generated package has large closure

Solution:

# Production mode (no dev deps)
node2nix --production -l package-lock.json

# Strip optional dependencies
node2nix --strip-optional-dependencies
# Remove unnecessary build dependencies
{
  package = nodePackages.package.override {
    dontNpmInstall = true;

    installPhase = ''
      # Install only what's needed
      mkdir -p $out
      cp -r dist $out/
      cp package.json $out/
    '';
  };
}

15. Advanced Usage

Custom Composition

# Generate with custom composition file
node2nix -c my-composition.nix

# Allows custom package structure

Patch Packages

{ pkgs ? import <nixpkgs> {} }:

let
  nodePackages = import ./node-packages.nix {
    inherit pkgs;
    inherit (pkgs) system fetchurl fetchgit stdenv lib;
  };
in
{
  package = nodePackages.package.overrideAttrs (oldAttrs: {
    patches = [
      ./patches/fix-vulnerability.patch
    ];

    postPatch = ''
      # Patch package.json
      substituteInPlace package.json \
        --replace "old-version" "new-version"
    '';
  });
}

Multi-Platform Support

{ pkgs ? import <nixpkgs> {} }:

let
  nodePackages = import ./node-packages.nix {
    inherit pkgs;
    inherit (pkgs) system fetchurl fetchgit stdenv lib;
  };

  # Platform-specific overrides
  package = if pkgs.stdenv.isDarwin
    then nodePackages.package.override {
      buildInputs = with pkgs.darwin.apple_sdk.frameworks; [
        CoreServices
        Foundation
      ];
    }
    else nodePackages.package;
in
{
  inherit package;
}

Development vs Production Builds

# default.nix
{ pkgs ? import <nixpkgs> {}
, production ? true
}:

let
  nodePackages = import ./node-packages.nix {
    inherit pkgs;
    inherit (pkgs) system fetchurl fetchgit stdenv lib;
  };
in
{
  package = nodePackages.package.override {
    buildPhase = if production
      then ''
        export NODE_ENV=production
        npm run build
      ''
      else ''
        export NODE_ENV=development
        npm run build:dev
      '';
  };
}

Best Practices

DO ✅

  1. Always use lock files

``bash node2nix -l package-lock.json ``

  1. Version control generated files

``bash git add node-packages.nix node-env.nix default.nix git commit -m "Add Nix expressions for Node.js project" ``

  1. Use production mode for deployments

``bash node2nix --production -l package-lock.json ``

  1. Override packages with native deps

``nix buildInputs = [ pkgs.python3 pkgs.cairo ]; ``

  1. Test in nix-shell before building

``bash nix-shell -A shell npm test ``

  1. Pin nixpkgs version

``nix pkgs ? import (fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/COMMIT.tar.gz";; sha256 = "..."; }) {} ``

  1. Document overrides and customizations

``nix # Override for canvas - requires Cairo buildInputs = [ pkgs.cairo ]; ``

  1. Use flakes for modern projects

``nix inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; ``

  1. Separate development and production configs

``bash # dev: node2nix --development # prod: node2nix --production ``

  1. Keep node2nix up to date

``bash nix-env -u nodePackages.node2nix ``

DON'T ❌

  1. Don't commit node_modules

``bash # .gitignore node_modules/ ``

  1. Don't skip lock files

```bash # ❌ Bad node2nix

# ✅ Good node2nix -l package-lock.json ```

  1. Don't ignore build failures silently

```nix # ❌ Bad - hides issues dontBuild = true;

# ✅ Good - fix the issue buildInputs = [ requiredDeps ]; ```

  1. Don't hardcode paths

```nix # ❌ Bad "/usr/bin/node"

# ✅ Good "${pkgs.nodejs}/bin/node" ```

  1. Don't mix npm and nix package management

``bash # ❌ Don't run npm install manually # ✅ Let Nix handle it ``

  1. Don't commit secrets

``bash # Never commit tokens or auth # Use environment variables or secrets management ``

  1. Don't skip regeneration after updates

``bash # After npm install/update: node2nix -l package-lock.json ``

Command Reference

# Basic usage
node2nix                                    # Generate from package.json
node2nix -l package-lock.json              # Use lock file
node2nix --development                      # Include devDependencies
node2nix -i packages.json                  # Custom input file

# Node.js versions
node2nix -4                                 # Node.js 4.x
node2nix -6                                 # Node.js 6.x
node2nix -8                                 # Node.js 8.x

# Registry configuration
node2nix --registry URL                     # Custom registry
node2nix --registry-auth-token TOKEN        # Auth token
node2nix --registry-scope SCOPE            # Scoped packages

# Dependency handling
node2nix --include-peer-dependencies       # Include peers
node2nix --strip-optional-dependencies     # Remove optional
node2nix --bypass-cache                    # Force fresh fetch

# Advanced
node2nix --use-fetchgit-private            # Private git repos
node2nix --supplement-input FILE           # Additional packages
node2nix --no-copy-node-env                # Smaller closure

# Output control
node2nix -o node-packages.nix              # Custom output
node2nix -c composition.nix                # Custom composition
node2nix -e node-env.nix                   # Custom environment

# Help
node2nix --help                            # Show help
node2nix --version                         # Show version

Success Metrics

  • Reproducible Builds: Same package.json → same output
  • Declarative: Everything in Nix expressions
  • Version Controlled: Generated files tracked in git
  • Integrated: Works with NixOS, flakes, home-manager
  • Tested: Builds successfully in clean environment
  • Documented: Overrides and customizations explained

Ready to convert NPM packages to Nix with node2nix! 📦