示例版本与验证范围#
本教程保留 NixOS/Home Manager 24.05 分支示例,展示结构而非推荐部署这个历史版本。实际配置应使用相互匹配且受支持的分支,保留原有 stateVersion,并按锁定版本检查接口。占位 commit/hash 和省略号需要替换;代码未在目标系统构建或运行验证。
本章是 Nix 最重要的进步。Flakes 提供了可复现的、版本锁定的项目定义方式。
什么是 Flakes?#
Flakes 是 Nix 的实验性功能,提供了:
- 可复现性:所有依赖通过 flake.lock 锁定
- 可组合性:轻松组合多个项目
- 标准化:统一的输入/输出接口
启用 Flakes#
NixOS 系统
# /etc/nixos/configuration.nix
{ pkgs, ... }: {
nix.settings.experimental-features = [ "nix-command" "flakes" ];
# 允许非自由软件
nixpkgs.config.allowUnfree = true;
}非 NixOS 系统
# ~/.config/nix/nix.conf
experimental-features = nix-command flakes或通过命令行参数临时启用:
nix --extra-experimental-features "nix-command flakes" <命令>Flake 文件结构#
基本语法
{
# === 输入依赖 ===
inputs = {
# 标准格式: type:location?ref
# type = github, gitlab, sourcehut, git, path, etc.
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
# 本地路径
my-package.url = "path:./my-package";
# Git 仓库
my-project.url = "git+https://github.com/user/repo?ref=main";
};
# === 输出定义 ===
outputs = { self, nixpkgs, ... }@inputs: {
# packages, devShells, nixosConfigurations, etc.
};
}完整示例
{
description = "我的项目";
# ========== 输入依赖 ==========
inputs = {
# nixpkgs 官方包集合
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
# 跟随 nixpkgs(使用同一版本)
home-manager = {
url = "github:nix-community/home-manager/release-24.05";
inputs.nixpkgs.follows = "nixpkgs";
};
# 锁定到特定 commit
nixpkgs-old.url = "github:NixOS/nixpkgs/a1b2c3d4";
# 本地 Flake
my-local.url = "path:/home/user/my-flake";
};
# ========== 输出定义 ==========
outputs = { self, nixpkgs, home-manager, ... }@inputs:
let
# 定义系统平台
supportedSystems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
# 为每个系统生成配置(自动化工具)
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
# 获取对应平台的 nixpkgs
pkgsFor = system: nixpkgs.legacyPackages.${system};
in
{
# === 软件包 ===
packages = forAllSystems (system: {
default = (pkgsFor system).callPackage ./default.nix {};
my-app = (pkgsFor system).callPackage ./my-app.nix {};
});
# === 开发环境 ===
devShells = forAllSystems (system: {
default = (pkgsFor system).mkShell {
packages = with (pkgsFor system); [
git nodejs jq
];
};
});
# === NixOS 配置 ===
nixosConfigurations.my-server = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
home-manager.nixosModules.home-manager
];
specialArgs = { inherit inputs; };
};
# === Home Manager 配置 ===
homeConfigurations.alice = home-manager.lib.homeManagerConfiguration {
pkgs = nixpkgs.legacyPackages.x86_64-linux;
modules = [ ./home.nix ];
extraSpecialArgs = { inherit inputs; };
};
# === 格式化检查 ===
formatter = forAllSystems (system: (pkgsFor system).alejandra);
};
}输入(Inputs)详解#
常见输入源
{
inputs = {
# GitHub(最常用)
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
# 指定分支/标签/commit
nixpkgs-unstable.url = "github:NixOS/nixpkgs/master";
nixpkgs-some-commit.url = "github:NixOS/nixpkgs/abc123def";
# GitLab
gitlab-repo.url = "gitlab:owner/repo/main";
# SourceHut
srht-repo.url = "sourcehut:owner/repo";
# 任意 Git 仓库
my-git.url = "git+https://example.com/repo.git?ref=main";
my-git-ssh.url = "git+ssh://git@github.com/owner/repo";
# 本地路径
local-pkg.url = "path:./local-package";
# 跟随其他输入(避免重复下载)
home-manager = {
url = "github:nix-community/home-manager/release-24.05";
# 使用与 nixpkgs 相同的版本
inputs.nixpkgs.follows = "nixpkgs";
};
# 禁用某些输入
some-input.inputs.unused.follows = "";
};
}输入属性
{
inputs = {
my-input = {
url = "github:owner/repo";
# 将内容当作普通源码而非 Flake;固定 commit 应写入 URL/rev
flake = false; # 非 flake 输入(纯内容)
# 子目录
# 使用 Flake 子目录(URL 查询参数)
# url = "github:owner/repo?dir=subdirectory";
};
};
}Flake 命令详解#
基础命令
# 查看 flake 信息
nix flake info
nix flake metadata
# 仅检查求值,不构建 checks
nix flake check --no-build
# 求值并构建 checks(不激活系统)
nix flake check
# 更新所有依赖
nix flake update
# 更新特定输入
nix flake update nixpkgs
nix flake update home-manager
# 编辑 flake
nix flake edit
# 克隆 flake 仓库
nix flake clone <flake-url>
# 显示 flake 目录
nix flake init # 在当前目录初始化构建命令
# 构建默认包
nix build
# 构建特定包
nix build .#my-package
nix build .#packages.x86_64-linux.my-app
# 构建并输出路径
nix build .#my-package --out-link ./result
# 构建并打印路径
nix build .#my-package --print-out-paths
# 从其他 flake 构建
nix build github:nixos/nixpkgs#hello
nix build gitlab:owner/repo#package运行命令
# 运行默认包
nix run
# 运行特定包
nix run .#my-app
# 运行临时软件包(不安装)
nix run nixpkgs#htop
nix run nixpkgs#nodejs -- --version
nix run nixpkgs#cowsay -- "Hello Nix"
# 从 URL 运行
nix run github:owner/repo#script开发环境
# 进入开发环境
nix develop
nix develop .#default
# 进入特定 shell
nix develop .#python-dev
# 临时进入环境执行命令
nix develop --command cargo build
nix develop .#rust --command rustc --version
# nix shell 是新 CLI 的临时包环境,与 nix develop 不同
nix shell .#my-package
nix shell nixpkgs#git nixpkgs#vim系统配置
# NixOS
sudo nixos-rebuild switch --flake .#my-host
sudo nixos-rebuild build --flake .#my-host
sudo nixos-rebuild test --flake .#my-host
# 查看系统配置
nixos-rebuild build-vm --flake .#my-host
# Home Manager
home-manager switch --flake .#username
home-manager build --flake .#username
# Darwin (nix-darwin)
darwin-rebuild switch --flake .#my-macNixOS Flake 配置#
单主机配置
# flake.nix
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
outputs = { self, nixpkgs }: {
nixosConfigurations.my-laptop = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
{
# 自动传递 self 作为 specialArgs
_module.args.self = self;
}
];
};
};
}多主机配置
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
inputs.home-manager.url = "github:nix-community/home-manager/release-24.05";
outputs = { self, nixpkgs, home-manager }:
let
mkSystem = { hostname, system, users }: nixpkgs.lib.nixosSystem {
inherit system;
modules = [
./hosts/${hostname}/hardware-configuration.nix
./hosts/${hostname}/configuration.nix
./modules/common
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users = nixpkgs.lib.genAttrs users (user:
import ./home/${user}.nix
);
}
];
specialArgs = { inherit self; };
};
in
{
nixosConfigurations = {
# 笔记本
laptop = mkSystem {
hostname = "laptop";
system = "x86_64-linux";
users = [ "alice" ];
};
# 台式机
desktop = mkSystem {
hostname = "desktop";
system = "x86_64-linux";
users = [ "alice" "bob" ];
};
# 服务器
server = mkSystem {
hostname = "server";
system = "x86_64-linux";
users = [ "deploy" ];
};
};
};
}模块化 Flake#
目录结构
~/nixos-config/
├── flake.nix # 入口
├── flake.lock # 锁定文件
├── lib/ # 自定义库函数
│ └── default.nix
├── modules/ # 可复用模块
│ ├── core/ # 核心系统配置
│ ├── desktop/ # 桌面环境
│ ├── development/ # 开发环境
│ └── services/ # 服务
├── hosts/ # 主机特定配置
│ ├── laptop/
│ │ ├── default.nix
│ │ └── hardware-configuration.nix
│ └── server/
│ ├── default.nix
│ └── hardware-configuration.nix
├── home/ # Home Manager 配置
│ ├── alice.nix
│ └── bob.nix
└── pkgs/ # 自定义包
└── default.nix模块化入口
# flake.nix
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
outputs = inputs@{ self, nixpkgs }:
let
inherit (nixpkgs) lib;
# 系统类型
systems = [ "x86_64-linux" "aarch64-linux" ];
# 为每个系统应用函数
forEachSystem = f: lib.genAttrs systems (sys: f nixpkgs.legacyPackages.${sys});
in
{
# 导入 lib
lib = import ./lib { inherit lib; };
# 导入包
packages = forEachSystem (pkgs: import ./pkgs { inherit pkgs; });
# NixOS 配置
nixosConfigurations = {
laptop = lib.nixosSystem {
system = "x86_64-linux";
modules = [
# 核心模块
./modules/core
./modules/desktop
./modules/development
# 主机特定
./hosts/laptop
# 本地包
{ nixpkgs.overlays = [ self.overlays.default ]; }
];
specialArgs = { inherit self inputs; };
};
};
# Overlay
overlays.default = final: prev: {
my-packages = self.packages.${final.system};
};
};
}Flake.lock 详解#
锁定文件结构
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1698611440,
"narHash": "sha256-...",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a1b2c3d4...",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}锁定命令
# 创建/更新锁定
nix flake lock
# 更新特定输入
nix flake update nixpkgs
# 使用特定版本
# 临时覆盖不写入锁文件;持久固定请先修改 flake.nix
nix flake metadata --override-input nixpkgs github:NixOS/nixpkgs/<rev>
# 从锁定文件恢复
nix flake metadata --reference-lock-file ./old-flake.lock
# 查看锁定信息
nix flake metadata --json实际使用示例#
项目模板
# flake.nix - Python 项目
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
outputs = { self, nixpkgs }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
python = pkgs.python311;
my-python-packages = ps: with ps; [
requests
flask
pytest
black
mypy
];
in
{
devShells.${system}.default = pkgs.mkShell {
name = "python-project";
packages = with pkgs; [
(python.withPackages my-python-packages)
git
just # 命令运行器
];
shellHook = ''
# python.withPackages 的包装器提供声明的包。
# 不设置虚假的 VIRTUAL_ENV;如需 venv,应单独创建并激活。
echo "Python 开发环境已加载"
python --version
'';
};
packages.${system}.default = pkgs.python311Packages.buildPythonApplication {
pname = "my-app";
version = "1.0.0";
src = ./.;
propagatedBuildInputs = with pkgs.python311Packages; [
requests flask
];
};
};
}完整系统配置
# flake.nix
{
description = "NixOS 完全配置";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
home-manager = {
url = "github:nix-community/home-manager/release-24.05";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-doom-emacs = {
url = "github:nix-community/nix-doom-emacs";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = inputs@{ self, nixpkgs, home-manager, ... }:
let
lib = nixpkgs.lib;
mkSystem = { config, system ? "x86_64-linux" }: lib.nixosSystem {
inherit system;
modules = [
config
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
# 自动传递 inputs
_module.args.inputs = inputs;
}
];
};
in
{
nixosConfigurations = {
laptop = mkSystem {
config = ./hosts/laptop;
};
work = mkSystem {
config = ./hosts/work;
};
};
# 格式化工具
formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.alejandra;
# 模板
templates.default = {
path = ./templates/basic;
description = "基础项目模板";
};
};
}常见问题#
如何查看 flake 提供的输出?
nix flake show
nix flake show github:owner/repo如何调试构建失败?
# 进入项目开发环境(不等于自动复现失败 derivation 的完整环境)
nix develop .#devShells.x86_64-linux.default -L
# 查看详细日志
nix build .#package --print-build-logs
nix build .#package -L如何引用本地路径?
{
inputs.local-pkg.url = "path:/absolute/path/to/package";
# 或相对路径
inputs.my-config.url = "path:./my-config";
}如何兼容旧版入口?
nix-build 不会自动把 Flake 转换成传统表达式。项目需要提供 default.nix/shell.nix,可使用 flake-compat 适配锁定的 Flake;适配后才使用:
nix-build最佳实践#
- 始终锁定版本:使用
nix flake lock - 分离系统配置:每个主机独立目录
- 使用 follows:避免重复下载
- 定期更新:但不要盲目更新
- 备份 lock 文件:版本控制中保留
参考与延伸
根据技术笔记重新整理,示例使用通用名称。