Claude
Skills
Sign in
Back

nix-packaging-best-practices

Included with Lifetime
$97 forever

Best practices for packaging pre-compiled binaries (.deb, .rpm, .tar.gz, AppImage) for NixOS, handling library dependencies, or facing "library not found" errors with binary distributions

General

What this skill does


# Packaging Binary Distributions for Nix

Extract and patch binary packages within Nix builds for reproducibility.

## Core Principle

**Source from original archive directly, never from pre-extracted directories.**

## When to Use

- Converting binary packages (.deb, .rpm, .tar.gz, .zip) to Nix derivations
- Packaging proprietary/closed-source software distributed as binaries
- Electron/GUI apps show "library not found" errors
- User provides pre-extracted binary contents
- Binary distributions need library path fixes

**Don't use for:**
- Software available in nixpkgs
- Source-based packages (use standard derivation)
- AppImages (use appimage-run or extract and patch)

## Quick Reference

| Topic | Rule File |
|-------|-----------|
| Core pattern for .deb packages | [essential-pattern](rules/essential-pattern.md) |
| .rpm, .tar.gz, .zip extraction | [archive-formats](rules/archive-formats.md) |
| nativeBuildInputs vs buildInputs | [dependencies](rules/dependencies.md) |
| Local vs remote source files | [source-files](rules/source-files.md) |
| Common pitfalls and fixes | [common-mistakes](rules/common-mistakes.md) |
| Finding missing libraries with ldd | [finding-libraries](rules/finding-libraries.md) |
| Quick testing with steam-run | [quick-testing](rules/quick-testing.md) |
| Troubleshooting autoPatchelf errors | [troubleshooting-autoPatchelf](rules/troubleshooting-autoPatchelf.md) |
| Version variable in filename | [version-management](rules/version-management.md) |
| Electron app dependencies | [electron-apps](rules/electron-apps.md) |
| FHS env for resistant binaries | [advanced-fhs-env](rules/advanced-fhs-env.md) |
| Build phases and hooks | [build-phases](rules/build-phases.md) |
| Wrapper scripts with makeWrapper | [wrapper-programs](rules/wrapper-programs.md) |

## Essential Pattern (.deb)

```nix
{ pkgs }:

pkgs.stdenv.mkDerivation rec {
  pname = "appname";
  version = "1.0.0";

  src = ./AppName-${version}-linux-amd64.deb;

  nativeBuildInputs = with pkgs; [
    autoPatchelfHook  # Fixes library paths
    dpkg              # Extracts .deb
  ];

  buildInputs = with pkgs; [
    stdenv.cc.cc.lib
    glib
    gtk3
  ];

  unpackPhase = ''
    ar x $src
    tar xf data.tar.xz
  '';

  installPhase = ''
    mkdir -p $out
    cp -r opt/AppName/* $out/
  '';
}
```

## Common Tasks

| Task | Solution |
|------|----------|
| Local archive | `src = ./package-${version}.tar.gz` |
| Remote archive | `src = fetchurl { url = "..."; hash = "sha256-..."; }` |
| Extract .deb | `ar x $src && tar xf data.tar.xz` + dpkg |
| Extract .rpm | `rpm2cpio $src \| cpio -idmv` + rpm, cpio |
| Extract .tar.gz | Auto-detected by stdenv |
| Extract .zip | Add `unzip` to nativeBuildInputs |
| Fix libraries | Add `autoPatchelfHook` to nativeBuildInputs |
| Find missing libs | Run `ldd result/bin/app` for "not found" |
| Quick test binary | `nix-shell -p steam-run; steam-run ./binary` |
| Debug autoPatchelf | `nix log /nix/store/...-drv` |
| Search libraries | `nix-locate libX11.so.6` |
| Wrapper scripts | Add `makeWrapper` to nativeBuildInputs |
| Version sync | Use `src = ./app-${version}.tar.gz` |

## Dependency Categories

**nativeBuildInputs**: Build-time tools (dpkg, autoPatchelfHook, makeWrapper)
**buildInputs**: Runtime libraries (gtk3, glib, libpulseaudio)
**propagatedBuildInputs**: Rarely needed for binary packaging

## Common Library Mappings

| Missing Library | Nix Package |
|-----------------|-------------|
| `libgtk-3.so.0` | `gtk3` |
| `libglib-2.0.so.0` | `glib` |
| `libpulse.so.0` | `libpulseaudio` |
| `libGL.so.1` | `mesa` or `libglvnd` |
| `libxkbcommon.so.0` | `libxkbcommon` (NOT xorg.libxkbcommon) |
| `libstdc++.so.6` | `stdenv.cc.cc.lib` |

## Red Flags - STOP

- "User already extracted it, use that directory" → NO, source from original archive
- "Absolute path works for me locally" → Breaks for others, use relative
- "Just add more libraries until it works" → Find actual dependencies with `ldd`

## How to Use

Read individual rule files for detailed explanations and code examples:

```
rules/essential-pattern.md
rules/archive-formats.md
rules/_sections.md
```

Each rule file contains:
- Brief explanation of why it matters
- Incorrect code example with explanation
- Correct code example with explanation
- Additional context and references

## Full Compiled Document

For the complete guide with all rules expanded: `AGENTS.md`

Related in General