practical nix flakes
If you are running nixos, you already have the nix build system. Otherwise, you'll need to install it
curl -L https://nixos.org/nix/install | sh
Now you'll need to enable flakes
mkdir -p ~/.config/nix
echo "experimental-features = nix-command flakes" > ~/.config/nix/nix.conf
# now nix flake command should work
nix flake --help
For setup, that's pretty much all you need to do. If you already have a project with a working flake.nix
file then you are off to the races.
# build the default target
nix build
# enter quick shell with dependencies available
nix shell
# enter development shell for reproducable builds
nix develop
But what if you don't have a flake file yet? Here are some examples for various programming languages.
ruby
To generate the gemset.nix you'll need to use bundix: nix-shell -p bundix
{
description = "A Ruby on Rails project";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
system = "x86_64-linux"; # Adjust the system if necessary
pkgs = import nixpkgs {
inherit system;
};
# Specify the Ruby version you want to use
ruby = pkgs.ruby_3_2; # As an example, using Ruby 3.2
# Define the Ruby on Rails environment
railsEnv = pkgs.bundlerEnv {
name = "my-rails-app";
inherit ruby;
gemfile = ./Gemfile;
lockfile = ./Gemfile.lock;
gemset = ./gemset.nix; # Generated from Gemfile.lock
};
in
{
packages.${system}.default = railsEnv;
defaultPackage.${system} = railsEnv;
# Define a development shell environment
devShells.${system} = pkgs.mkShell {
buildInputs = [
railsEnv # This provides the Ruby environment with all gems specified in Gemfile
# Include other build inputs like databases, etc.
];
};
};
}
python
{
description = "A Python project with Numpy and Pandas";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
system = "x86_64-linux";
# Obtain the package set from nixpkgs
pkgs = import nixpkgs {
inherit system;
};
# Function to create a Python environment
pythonEnv = pkgs.python3.withPackages (ps: with ps; [
numpy
pandas
# You can add more Python packages here, e.g., matplotlib, scipy, etc.
]);
in
{
packages.${system}.default = pythonEnv;
defaultPackage.${system} = pythonEnv;
# Define a development shell for `nix develop`
devShells.${system} = pkgs.mkShell {
buildInputs = [ pythonEnv ];
# Set PYTHONPATH to make sure Python can find the installed packages
shellHook = ''
export PYTHONPATH=${pythonEnv}/${pkgs.python3.sitePackages}
'';
};
};
}
nodejs
{
description = "A Node.js project";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
};
nodePackages = pkgs.nodePackages // {
package = pkgs.nodePackages.package.override {
src = self;
};
};
# Create the development environment
devShell = pkgs.mkShell {
buildInputs = [
pkgs.nodejs_20
];
# The following line can be uncommented to automatically install npm dependencies
# shellHook = ''
# npm install
# '';
};
in
{
packages.${system}.default = nodePackages;
devShells.${system}.default = devShell;
};
}
java
{
description = "A simple Java project";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
# Import nixpkgs
pkgs = import nixpkgs {
system = "x86_64-linux";
};
# Define the Java environment
javaEnv = pkgs.mkShell {
buildInputs = [ pkgs.jdk19_headless pkgs.maven ];
};
in
{
packages.x86_64-linux.default = pkgs.stdenv.mkDerivation {
pname = "my-java-app";
version = "1.0";
src = self;
# Set JAVA_HOME
buildInputs = [ pkgs.jdk19_headless pkgs.maven ];
# The build phase
buildPhase = ''
mvn compile
'';
# The install phase
installPhase = ''
mvn package
'';
};
# Define a development shell for `nix develop`
devShells.x86_64-linux = javaEnv;
};
}
Note: nix build will not have internet access to the maven repo, so you'll need to download the packages with mvn dependency:go-offline
rust
{
description = "A basic Rust application";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
# Import nixpkgs for the x86_64-linux system
pkgs = import nixpkgs {
system = "x86_64-linux";
};
# Define the Rust package
rustPackage = pkgs.rustPlatform.buildRustPackage {
pname = "my-rust-app";
version = "0.1.0";
src = pkgs.lib.cleanSource ./.;
# The hash for Cargo.lock
cargoSha256 = "w9sBUL9eYOjFDNBhB35JImFjexnKM0nY7C7idCXNyKg=";
# Set release mode explicitly, though it is the default
cargoBuildFlags = [ "--release" ];
};
in
{
packages.x86_64-linux.default = rustPackage;
defaultPackage.x86_64-linux = rustPackage;
# Define a development environment for this project
devShells.x86_64-linux = pkgs.mkShell {
buildInputs = [
pkgs.rustc
pkgs.cargo
# Include any other dependencies here
];
};
};
}
c++
{
description = "A C++ project with CMake and GCC";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
# Import the nixpkgs for the specified system
system = "x86_64-linux"; # Change this to your specific system if needed
pkgs = import nixpkgs {
inherit system;
};
# Create the development environment
devEnv = pkgs.mkShell {
nativeBuildInputs = [
pkgs.cmake
pkgs.gcc
pkgs.make
# Add any other dependencies your project may need, e.g.:
# pkgs.boost
# pkgs.eigen
# etc.
];
# Optionally set environment variables, like:
# CXXFLAGS="-O3"
# LDFLAGS="-flto"
};
in
{
# The default package to build
packages.${system}.default = pkgs.stdenv.mkDerivation {
pname = "my-cpp-app";
version = "1.0";
src = self; # or ./. if you want to point to the root of the project
nativeBuildInputs = [ pkgs.cmake pkgs.gcc ];
# The build phase (CMake in this case)
buildPhase = ''
cmake .
make
'';
# The install phase
installPhase = ''
mkdir -p $out/bin
cp my-cpp-app $out/bin/
'';
# You can specify more phases like checkPhase for tests, if necessary.
};
# Define the development shell for `nix develop`
devShells.${system} = devEnv;
# The default application when running `nix run`
defaultApp.${system} = self.packages.${system}.default;
};
}
c++ cross compiling for x86 and aarch64
{
description = "A C++ project with cross-compilation for aarch64-linux";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
# Cross-compilation target
crossSystem = "aarch64-linux";
# Import nixpkgs for the host system
hostPkgs = import nixpkgs {
system = "x86_64-linux";
overlays = [];
};
# Import nixpkgs with cross-compilation support
crossPkgs = import nixpkgs {
system = "x86_64-linux";
crossSystem = {
config = crossSystem;
# Additional cross-compilation configuration goes here
};
};
in {
packages.x86_64-linux = {
my-cpp-app = hostPkgs.stdenv.mkDerivation {
pname = "my-cpp-app";
version = "1.0";
src = self;
nativeBuildInputs = with hostPkgs; [ cmake pkg-config ];
buildInputs = with hostPkgs; [
# Dependencies for the target architecture
];
buildPhase = ''
cmake .
make
'';
installPhase = ''
mkdir -p $out/bin/x86
cp my-cpp-app $out/bin/x86
'';
};
my-cpp-app-aarch64 = crossPkgs.stdenv.mkDerivation {
pname = "my-cpp-app";
version = "1.0";
src = self;
nativeBuildInputs = with hostPkgs; [ cmake pkg-config ];
buildInputs = with crossPkgs; [
# Dependencies for the target architecture
];
buildPhase = ''
cmake .
make
'';
installPhase = ''
mkdir -p $out/bin/arm
cp my-cpp-app $out/bin/arm
'';
};
};
# Define the development shell for `nix develop`
devShells.x86_64-linux = hostPkgs.mkShell {
nativeBuildInputs = with hostPkgs; [ cmake pkg-config ];
};
};
}
The arm target can be compiled by specifying the target
# build for x86
nix build .\#my-cpp-app
# build for arm
nix build .\#my-cpp-app-aarch64