How do you install a one-off package in NixOS?
How to Install a One-Off Package in NixOS
As NixOS enthusiasts, we often find ourselves in situations where we need a specific package version that’s not readily available in our current stable channel. Perhaps a particular application requires a newer release, or we want to experiment with a cutting-edge version before it’s officially integrated. Staying on a stable channel like nixos-16.03 provides reliability, but it can sometimes lag behind the latest package offerings. In this comprehensive guide, we’ll explore various methods to install one-off packages in NixOS without compromising the stability of your system or hindering future upgrades. We aim to provide a detailed, practical approach to address this common challenge.
Understanding the NixOS Package Management Paradigm
Before diving into the solutions, it’s essential to grasp the fundamental principles behind NixOS’s package management. NixOS uses a purely functional approach, meaning that every package is built from its source code with all dependencies declared explicitly. This results in reproducible builds and eliminates dependency conflicts. The Nix package manager stores packages in the Nix store (/nix/store), identified by content-addressed hashes. This unique storage mechanism allows multiple versions of the same package to coexist peacefully on the system.
The Role of Channels
NixOS channels are essentially pointers to specific snapshots of the Nix Packages collection (nixpkgs). Each channel represents a set of package versions that have been tested and deemed stable for a particular release. Staying on a stable channel ensures that your system receives consistent updates and avoids introducing potentially unstable software. However, this stability comes at the cost of immediate access to the newest package releases.
Addressing the One-Off Package Installation Challenge
The core challenge lies in installing a package version newer than what’s available in our stable channel (e.g., nixos-16.03) without disrupting the overall system stability or hindering future upgrades when the stable channel catches up. Let’s explore several strategies to tackle this problem.
Method 1: Overriding Package Attributes in configuration.nix
As suggested in the IRC conversation, overriding the src and version attributes within your configuration.nix file is a viable option for packages that already exist in your current channel. This approach leverages Nix’s attribute overriding mechanism to customize the package build process.
Step-by-Step Implementation
Locate the Package Definition: Identify the existing Nix expression for the package you want to override. This can typically be found in the nixpkgs repository on GitHub or by inspecting the output of
nix-env -qaP \*packagename\*.Override
srcandversion: Add an overlay to yourconfiguration.nixfile to override thesrcandversionattributes of the package. Here’s an example usingnodejs-6_xas the target package:{ config, pkgs, ... }: { nixpkgs.overlays = [ (self: super: { nodejs-6_x = super.nodejs-6_x.overrideAttrs (oldAttrs: { version = "6.22.12"; # Replace with the desired version src = pkgs.fetchurl { url = "https://nodejs.org/dist/v6.22.12/node-v6.22.12.tar.gz"; # Replace with the appropriate URL for the desired version sha256 = "000000000000000000000000000000000000000000000000000000000000"; # Replace with the correct SHA256 hash }; }); }) ]; }nixpkgs.overlays: This setting allows you to modify the package set defined by nixpkgs. Overlays are functions that take the original nixpkgs set and return a modified version.(self: super: { ... }): This is a lambda function that receivesself(the modified nixpkgs) andsuper(the original nixpkgs).nodejs-6_x = super.nodejs-6_x.overrideAttrs (oldAttrs: { ... }): This line accesses the originalnodejs-6_xpackage fromsuperand usesoverrideAttrsto modify its attributes. TheoldAttrsargument provides access to the original attributes of the package.version = "6.22.12": This sets the desired version number.src = pkgs.fetchurl { ... }: This specifies the source code for the new version.url: The URL of the source code archive.sha256: The SHA256 hash of the source code archive. This is crucial for ensuring the integrity of the downloaded source code. You can obtain this hash usingnix-hash --type sha256 --flat <url>.
Calculate the SHA256 Hash: Use the
nix-hashcommand to compute the SHA256 hash of the source code archive:nix-hash --type sha256 --flat https://nodejs.org/dist/v6.22.12/node-v6.22.12.tar.gzReplace the URL with the actual URL of the package source. Paste the output of this command into the
sha256attribute in yourconfiguration.nixfile.Apply the Configuration: Rebuild your NixOS configuration to apply the changes:
sudo nixos-rebuild switch
Advantages
- Simple and straightforward for minor version updates.
- Keeps the package definition within your
configuration.nixfor easy management.
Disadvantages
- Requires manual intervention to update the
srcandversionattributes when a new version is released. - If the package definition undergoes significant changes in nixpkgs, your overlay might break.
Method 2: Defining a Custom Package Expression
When the package doesn’t exist in your current channel or requires substantial modifications, defining a custom Nix expression becomes necessary. This approach involves creating a .nix file that describes how to build the package from its source code.
Step-by-Step Implementation
Create a Package Directory: Create a directory in your home directory, for example
~/nixpkgs, to store your custom package definitions.Create a Nix Expression File: Inside the directory, create a
.nixfile (e.g.,nodejs-custom.nix) with the following content:{ pkgs ? import <nixpkgs> {} }: pkgs.stdenv.mkDerivation { name = "nodejs-6.22.12-custom"; version = "6.22.12"; src = pkgs.fetchurl { url = "https://nodejs.org/dist/v6.22.12/node-v6.22.12.tar.gz"; sha256 = "000000000000000000000000000000000000000000000000000000000000"; # Replace with the correct SHA256 hash }; buildPhase = '' ./configure make ''; installPhase = '' make install DESTDIR=$out ''; meta = with pkgs.lib; { description = "Custom build of Node.js 6.22.12"; homepage = "https://nodejs.org/"; license = licenses.mit; maintainers = with maintainers; [ revWhiteShadow ]; # Replace with your NixOS username }; }{ pkgs ? import <nixpkgs> {} }: This imports the nixpkgs set, allowing you to use functions and packages defined within it.pkgs.stdenv.mkDerivation { ... }: This uses the standard environment (stdenv) to create a derivation, which is a description of how to build the package.name: The name of the package. It’s good practice to include the version number in the name to avoid conflicts.version: The version number of the package.src: Specifies the source code for the package.buildPhase: The commands to execute during the build phase. This typically involves configuring and compiling the software.installPhase: The commands to execute during the install phase. This typically involves installing the compiled binaries and libraries to the$outdirectory, which represents the installation prefix.meta: Metadata about the package, such as its description, homepage, license, and maintainers.
Install the Custom Package: You can install the package using
nix-env:nix-env -i -f ~/nixpkgs/nodejs-custom.nixIntegrate into
configuration.nix(Optional): For system-wide availability, you can add the custom package to yourconfiguration.nixby including yournixpkgsdirectory in thenix.nixPath:{ config, pkgs, ... }: { nix.nixPath = [ "nixpkgs=/etc/nixos/nixpkgs" "/home/revWhiteShadow/nixpkgs" ]; # Replace revWhiteShadow with your username }Then, you can refer to the custom package in your system configuration:
{ config, pkgs, ... }: { environment.systemPackages = [ (import /home/revWhiteShadow/nixpkgs/nodejs-custom.nix).nodejs-6_x-custom ]; }
Advantages
- Provides maximum flexibility for customizing package builds.
- Allows you to install packages that don’t exist in the official channels.
Disadvantages
- Requires writing and maintaining your own Nix expressions.
- Can be more complex than simply overriding attributes.
Method 3: Using nix-build and nix-env -i
As you suggested, the combination of nix-build and nix-env -i can be a powerful way to install a one-off package. This method involves building a Nix expression directly from a URL or file and then installing the resulting package into your user environment.
Step-by-Step Implementation
Obtain the Nix Expression: Acquire the Nix expression for the desired package. This could be a URL pointing to a
.nixfile or a local file on your system. For example, let’s assume you have a Nix expression for Node.js athttps://example.com/nodejs.nix.Build the Package: Use
nix-buildto build the package from the Nix expression:nix-build https://example.com/nodejs.nixThis command will create a
resultsymlink in your current directory pointing to the built package in the Nix store.Install the Package: Use
nix-env -ito install the package into your user environment:nix-env -i -f ./result
Advantages
- Simple and concise for installing packages from external sources.
- Doesn’t require modifying your
configuration.nixfile.
Disadvantages
- The installed package is not managed by your system configuration and might not be automatically upgraded.
- The package will be installed in your user environment, not system-wide (unless you run the commands with
sudo).
Method 4: Using a Temporary Overlay with nix-shell
For temporary or experimental installations, using a temporary overlay with nix-shell offers a convenient way to access a modified package set without permanently altering your system configuration.
Step-by-Step Implementation
Create a
shell.nixfile: Create ashell.nixfile in your project directory with the following content:let pkgs = import <nixpkgs> { overlays = [ (self: super: { nodejs-6_x = super.nodejs-6_x.overrideAttrs (oldAttrs: { version = "6.22.12"; # Replace with the desired version src = pkgs.fetchurl { url = "https://nodejs.org/dist/v6.22.12/node-v6.22.12.tar.gz"; # Replace with the appropriate URL for the desired version sha256 = "000000000000000000000000000000000000000000000000000000000000"; # Replace with the correct SHA256 hash }; }); }) ]; }; in pkgs.mkShell { buildInputs = [ pkgs.nodejs-6_x ]; }Enter the Nix Shell: Run
nix-shellin the directory containing theshell.nixfile:nix-shellThis will create a temporary environment with the modified package set, where
nodejs-6_xwill be the overridden version.
Advantages
- Non-invasive and temporary.
- Ideal for testing and development purposes.
Disadvantages
- The modified package set is only available within the
nix-shellenvironment. - Not suitable for permanent system-wide installations.
Choosing the Right Method
The best method for installing a one-off package depends on your specific needs and preferences:
- Overriding Package Attributes: Suitable for minor version updates and when you want to keep the package definition within your
configuration.nix. - Defining a Custom Package Expression: Ideal for packages that don’t exist in the official channels or require substantial modifications.
- Using
nix-buildandnix-env -i: Convenient for installing packages from external sources without modifying your system configuration. - Using a Temporary Overlay with
nix-shell: Best for temporary or experimental installations.
Ensuring Future Upgradability
Regardless of the chosen method, it’s crucial to ensure that your system can be upgraded to newer versions of the package when the stable channel catches up. Avoid hardcoding specific versions in your system configuration whenever possible. Instead, rely on attribute overriding or custom package expressions that can be easily updated when necessary.
Leveraging NixOS’s Functional Nature
NixOS’s functional package management ensures that updates are applied atomically and reproducibly. When you upgrade your system, NixOS creates a new generation with the updated packages. If anything goes wrong, you can easily roll back to a previous generation.
Conclusion
Installing one-off packages in NixOS requires careful consideration to maintain system stability and ensure future upgradability. By understanding the different methods available and choosing the right approach for your specific needs, you can leverage the power and flexibility of NixOS without compromising its core principles. Remember to prioritize maintainability and avoid hardcoding version numbers whenever possible to ensure a smooth upgrade experience in the long run. By following the detailed steps outlined in this guide, you can confidently manage your NixOS packages and tailor your system to your specific requirements.