|
| 1 | +--- |
| 2 | +title: Package Priority |
| 3 | +description: How priority controls file conflict resolution in Flox environments |
| 4 | +--- |
| 5 | + |
| 6 | +When multiple packages install a file to the same path, |
| 7 | +Flox needs a rule to decide which one wins. |
| 8 | +That rule is **priority**. |
| 9 | + |
| 10 | +## How priority works |
| 11 | + |
| 12 | +A Flox environment is a directory of symlinks |
| 13 | +pointing into the Nix store. |
| 14 | +When the environment is built, |
| 15 | +every installed package's files are merged into this directory. |
| 16 | +If two packages both provide `bin/python` or `share/licenses/LICENSE`, |
| 17 | +their files collide. |
| 18 | + |
| 19 | +Priority resolves these collisions: |
| 20 | + |
| 21 | +- Every package has a `priority` value (default: **5**) |
| 22 | +- **Lower numbers win**. |
| 23 | + A package with `priority = 1` takes precedence |
| 24 | + over a package with `priority = 5` |
| 25 | +- If two packages collide at the **same priority**, |
| 26 | + Flox reports an error and the environment fails to build |
| 27 | + |
| 28 | +Priority only affects files that actually collide. |
| 29 | +Packages that install to non-overlapping paths coexist regardless |
| 30 | +of their priority values. |
| 31 | + |
| 32 | +## Setting priority |
| 33 | + |
| 34 | +Set priority in the `[install]` section of your manifest: |
| 35 | + |
| 36 | +```toml |
| 37 | +[install] |
| 38 | +gcc.pkg-path = "gcc" |
| 39 | + |
| 40 | +gcc-unwrapped.pkg-path = "gcc-unwrapped" |
| 41 | +gcc-unwrapped.priority = 6 |
| 42 | +``` |
| 43 | + |
| 44 | +Here `gcc` keeps the default priority of 5 |
| 45 | +and takes precedence over `gcc-unwrapped` (priority 6) |
| 46 | +for any overlapping files. |
| 47 | +Both packages are fully installed — |
| 48 | +only the conflicting files are resolved in favor of `gcc`. |
| 49 | + |
| 50 | +## When you need to set priority |
| 51 | + |
| 52 | +Most packages don't conflict, |
| 53 | +so you rarely need to think about priority. |
| 54 | +The situations where it matters are: |
| 55 | + |
| 56 | +### Overlapping packages |
| 57 | + |
| 58 | +Some packages provide subsets or supersets of each other. |
| 59 | +For example, |
| 60 | +`gcc` and `gcc-unwrapped` both install some of the same files. |
| 61 | +You may need both — |
| 62 | +`gcc` for the compiler and `gcc-unwrapped.lib` for `libstdc++` — |
| 63 | +but their overlapping files need a tiebreaker: |
| 64 | + |
| 65 | +```toml |
| 66 | +[install] |
| 67 | +gcc.pkg-path = "gcc" |
| 68 | + |
| 69 | +gcc-unwrapped.pkg-path = "gcc-unwrapped" |
| 70 | +gcc-unwrapped.priority = 6 |
| 71 | +gcc-unwrapped.pkg-group = "libraries" |
| 72 | +``` |
| 73 | + |
| 74 | +### CUDA packages |
| 75 | + |
| 76 | +CUDA packages are a common source of collisions |
| 77 | +because multiple packages install `LICENSE` files |
| 78 | +to the same path. |
| 79 | +When installing several CUDA packages, |
| 80 | +assign incremental priorities: |
| 81 | + |
| 82 | +```toml |
| 83 | +[install] |
| 84 | +cuda_nvcc.pkg-path = "flox-cuda/cudaPackages_12_8.cuda_nvcc" |
| 85 | +cuda_nvcc.systems = ["aarch64-linux", "x86_64-linux"] |
| 86 | +cuda_nvcc.priority = 1 |
| 87 | + |
| 88 | +cuda_cudart.pkg-path = "flox-cuda/cudaPackages.cuda_cudart" |
| 89 | +cuda_cudart.systems = ["aarch64-linux", "x86_64-linux"] |
| 90 | +cuda_cudart.priority = 2 |
| 91 | + |
| 92 | +cudatoolkit.pkg-path = "flox-cuda/cudaPackages_12_8.cudatoolkit" |
| 93 | +cudatoolkit.systems = ["aarch64-linux", "x86_64-linux"] |
| 94 | +cudatoolkit.priority = 3 |
| 95 | +``` |
| 96 | + |
| 97 | +The specific priority values don't matter |
| 98 | +as long as each package gets a distinct number. |
| 99 | +This tells Flox which `LICENSE` file to keep |
| 100 | +when they collide. |
| 101 | + |
| 102 | +### Cross-platform fallbacks |
| 103 | + |
| 104 | +When providing platform-specific alternatives |
| 105 | +(e.g. CUDA on Linux, CPU on macOS), |
| 106 | +priority can indicate which variant is preferred |
| 107 | +if both happen to be available: |
| 108 | + |
| 109 | +```toml |
| 110 | +[install] |
| 111 | +cuda-torch.pkg-path = "flox-cuda/python3Packages.torch" |
| 112 | +cuda-torch.systems = ["x86_64-linux", "aarch64-linux"] |
| 113 | +cuda-torch.priority = 1 |
| 114 | + |
| 115 | +torch-cpu.pkg-path = "python311Packages.torch-bin" |
| 116 | +torch-cpu.systems = ["x86_64-darwin", "aarch64-darwin"] |
| 117 | +torch-cpu.priority = 6 |
| 118 | +``` |
| 119 | + |
| 120 | +In practice the `systems` filter already prevents collisions here, |
| 121 | +but setting priority makes the intent explicit |
| 122 | +and protects against future changes. |
| 123 | + |
| 124 | +## Diagnosing collisions |
| 125 | + |
| 126 | +When two packages collide at the same priority, |
| 127 | +you'll see an error like: |
| 128 | + |
| 129 | +```text |
| 130 | + > ❌ ERROR: 'cuda13.0-cuda_nvcc' conflicts with 'cuda13.0-libcublas'. Both packages provide the file 'LICENSE' |
| 131 | + > Resolve by uninstalling one of the conflicting packages or setting the priority of the preferred package to a value lower than '5' |
| 132 | +``` |
| 133 | + |
| 134 | +To fix this, |
| 135 | +identify which package should win for the conflicting path |
| 136 | +and give it a lower priority number: |
| 137 | + |
| 138 | +```toml |
| 139 | +[install] |
| 140 | +packageA.pkg-path = "packageA" |
| 141 | +packageA.priority = 4 |
| 142 | + |
| 143 | +packageB.pkg-path = "packageB" |
| 144 | +packageB.priority = 6 |
| 145 | +``` |
| 146 | + |
| 147 | +## Priority and package groups |
| 148 | + |
| 149 | +Priority and [package groups][package-groups-concept] |
| 150 | +solve different problems: |
| 151 | + |
| 152 | +- **Package groups** control which `nixpkgs` revision |
| 153 | + each set of packages resolves against. |
| 154 | + They address version and ABI compatibility. |
| 155 | +- **Priority** controls which package's file wins |
| 156 | + when two packages install to the same path. |
| 157 | + It addresses file-level collisions |
| 158 | + in the merged environment. |
| 159 | + |
| 160 | +You can use both together. |
| 161 | +For example, |
| 162 | +`gcc-unwrapped` might need its own package group |
| 163 | +(to resolve against a different `nixpkgs` revision) |
| 164 | +_and_ a higher priority number |
| 165 | +(to let `gcc` win file conflicts): |
| 166 | + |
| 167 | +```toml |
| 168 | +[install] |
| 169 | +gcc.pkg-path = "gcc" |
| 170 | + |
| 171 | +gcc-unwrapped.pkg-path = "gcc-unwrapped" |
| 172 | +gcc-unwrapped.priority = 6 |
| 173 | +gcc-unwrapped.pkg-group = "libraries" |
| 174 | +``` |
| 175 | + |
| 176 | +## Priority and builds |
| 177 | + |
| 178 | +Priority has no effect on what is available |
| 179 | +during [manifest builds][manifest-builds-concept]. |
| 180 | +Only packages in the `toplevel` |
| 181 | +[package group][package-groups-concept] |
| 182 | +are available during builds, |
| 183 | +regardless of their priority. |
| 184 | + |
| 185 | +If you use `runtime-packages` to trim your build's closure, |
| 186 | +all listed packages are included at their assigned priorities. |
| 187 | + |
| 188 | +## Priority and composition |
| 189 | + |
| 190 | +When [composing environments][composition-concept], |
| 191 | +the included manifests are merged before the environment is built. |
| 192 | +If two environments define the same install ID |
| 193 | +(e.g. both provide `gcc.pkg-path`), |
| 194 | +the later environment's package descriptor overrides the earlier one |
| 195 | +during the manifest merge — |
| 196 | +this is a manifest-level override, |
| 197 | +not a file-level priority collision. |
| 198 | + |
| 199 | +After merging, |
| 200 | +the resulting environment is built |
| 201 | +and any file-level collisions between *different* packages |
| 202 | +are resolved by priority |
| 203 | +the same way they are in a non-composed environment. |
| 204 | + |
| 205 | +## Reference |
| 206 | + |
| 207 | +| Aspect | Detail | |
| 208 | +| ------ | ------ | |
| 209 | +| Default value | `5` | |
| 210 | +| Direction | Lower number = higher precedence | |
| 211 | +| Valid values | Integers (no fixed bounds) | |
| 212 | +| Common range | `1` through `10` | |
| 213 | +| Same-priority collision | Error — environment fails to build | |
| 214 | +| Scope | File paths only — doesn't affect resolution | |
| 215 | + |
| 216 | +### Nix equivalent |
| 217 | + |
| 218 | +Flox's `priority` maps directly to `meta.priority` in nixpkgs. |
| 219 | +The semantics are identical: |
| 220 | +default value of 5, lower wins, |
| 221 | +same-priority collisions produce errors. |
| 222 | + |
| 223 | +Nixpkgs provides convenience wrappers — |
| 224 | +`lib.meta.hiPrio` (sets priority to -10) and |
| 225 | +`lib.meta.lowPrio` (sets priority to 10) — |
| 226 | +but in Flox you set the integer directly in the manifest. |
| 227 | + |
| 228 | +[package-groups-concept]: ./package-groups.md |
| 229 | +[manifest-builds-concept]: ./manifest-builds.md |
| 230 | +[composition-concept]: ./composition.md |
0 commit comments