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
src
andversion
: Add an overlay to yourconfiguration.nix
file to override thesrc
andversion
attributes of the package. Here’s an example usingnodejs-6_x
as 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_x
package fromsuper
and usesoverrideAttrs
to modify its attributes. TheoldAttrs
argument 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-hash
command 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.gz
Replace the URL with the actual URL of the package source. Paste the output of this command into the
sha256
attribute in yourconfiguration.nix
file.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.nix
for easy management.
Disadvantages
- Requires manual intervention to update the
src
andversion
attributes 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
.nix
file (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$out
directory, 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.nix
Integrate into
configuration.nix
(Optional): For system-wide availability, you can add the custom package to yourconfiguration.nix
by including yournixpkgs
directory 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
.nix
file 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-build
to build the package from the Nix expression:nix-build https://example.com/nodejs.nix
This command will create a
result
symlink in your current directory pointing to the built package in the Nix store.Install the Package: Use
nix-env -i
to 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.nix
file.
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.nix
file: Create ashell.nix
file 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-shell
in the directory containing theshell.nix
file:nix-shell
This will create a temporary environment with the modified package set, where
nodejs-6_x
will 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-shell
environment. - 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-build
andnix-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.