NIX-STORE-OPTIMISE(1)

πŸ’– nix-store --optimise(1) πŸ’–

General Commands Manual β€” yes bestie, it's a real manual page, and it's lowkey iconic.


✨ NAME ✨

nix-store --optimise β€” reduce disk space usage πŸ—œοΈπŸ’…

🌸 SYNOPSIS 🌸

nix-store --optimise

πŸ¦‹ DESCRIPTION πŸ¦‹

Okay so the --optimise operation is the one that makes your Nix store ✨skinnier✨. It reduces Nix store disk space usage by finding identical files in the store and hard-linking them to each other. The way it typically does this? It reduces the size of the store by something like 25-35%. No cap, that's a whole glow-up for your SSD. πŸ”₯

Only regular files and symlinks get hard-linked in this manner β€” nothing else is out here getting linked, periodt.

So when are two files considered identical? Bestie, it's about the Nix Archive (NAR) serialisation: that is, regular files must have the same contents and permission (executable or non-executable), and symlinks must have the same contents. Same NAR vibe = same file, fr fr. 🫢

After completion, or when the command is interrupted, a report on the achieved savings is printed on standard error. So go ahead and look at stderr, that's where the receipts live. πŸ’€

Use -vv or -vvv to get some progress indication. More v's = more gossip about what's happening. πŸ‘€


πŸ‘‘ OPTIONS πŸ‘‘

The following options are allowed for all nix-store operations, but may not always have an effect. (like, they're always invited to the party, but sometimes they just vibe in the corner)

  • --add-root path

Causes the result of a realisation (--realise and --force-realise) to be registered as a root of the garbage collector. πŸ—‘οΈπŸš«

path will be created as a symlink to the resulting store path. In addition, a uniquely named symlink to path will be created in /nix/var/nix/gcroots/auto/. For instance,

$ nix-store --add-root /home/eelco/bla/result --realise ...

$ ls -l /nix/var/nix/gcroots/auto
lrwxrwxrwx    1 ... 2005-03-13 21:10 dn54lcypm8f8... -> /home/eelco/bla/result

$ ls -l /home/eelco/bla/result
lrwxrwxrwx    1 ... 2005-03-13 21:10 /home/eelco/bla/result -> /nix/store/1r11343n6qd4...-f-spot-0.0.10

Thus, when /home/eelco/bla/result is removed, the GC root in the auto directory becomes a dangling symlink and will be ignored by the collector. It simply stops being perceived. ghosted, honestly. πŸ«₯

⚠️ Warning ⚠️
Note that it is not possible to move or rename GC roots, since the symlink in the auto directory will still point to the old location. So don't try it!! The symlink remembers where you used to live and it is NOT updating its contact info. 😭

If there are multiple results, then multiple symlinks will be created by sequentially numbering symlinks beyond the first one (e.g., foo, foo-2, foo-3, and so on). Cute little numbered besties, one through infinity. πŸŽ€

πŸ’– COMMON OPTIONS πŸ’–

okay so like, most Nix commands accept this same lil squad of command-line options β€” think of them as the shared group chat that every Nix tool is in 🫢


  • --help β€” prints out a lil summary of the command syntax and then dips. bye bestie πŸ‘‹
  • --version β€” prints the Nix version number on standard output and exits. that's it, that's the tweet 🌟
  • --verbose / -v β€” turns the volume UP on the diagnostic messages that get printed to standard error. and here's the tea, bestie: for every Nix operation, whatever lands on standard output is well-defined β€” all the diagnostic noise goes to standard error</>, never to standard output. fr fr.

this option can be given more than once, and rn the vibes scale goes like this:

  • 0 β€œErrors only” β€” only tells you why the Nix invocation flopped. painful but necessary πŸ’€
  • 1 β€œInformational” β€” the useful stuff about what Nix is actually doing. this is the default, it's giving reliable πŸŽ€
  • 2 β€œTalkative” β€” more informational messages. she's chatty now πŸ’…
  • 3 β€œChatty” β€” even MORE informational messages. okay she's really talking 😭
  • 4 β€œDebug” β€” prints debug information. nerdy era πŸ”
  • 5 β€œVomit” β€” prints vast amounts of debug information. and yes, that is genuinely the name, no cap 🩸
  • --quiet β€” turns the volume DOWN on diagnostic messages printed to standard error. it's literally the inverse option to -v / --verbose. can also be given multiple times β€” same verbosity levels list as above, just walked backwards πŸ¦‹
  • --log-format format β€” changes the output of the log format, where format is one of these iconic options:
    • raw β€” the raw format, exactly as outputted by nix-build. plain, unbothered, moisturised 🌸
    • internal-json β€” outputs the logs in a structured manner. slay, structured queen ✨
⚠️ Warning β€” while the schema itself is relatively stable, the format of the error-messages (namely of the msg-field) can change between releases. so don't you dare parse it and then act surprised, bestie 😀
  • bar β€” only shows a progress bar during the builds. minimalism, we love her πŸŽ€
  • bar-with-logs β€” shows the raw logs, with the progress bar chillin' at the bottom. best of both worlds πŸ’œ
  • --no-build-output / -Q β€” by default, whatever the builders write to standard output and standard error gets echoed to the Nix command's standard error. this option suppresses that behaviour. but β€” and this is important β€” the builder's standard output and error are always written to a log file in prefix/nix/var/log/nix. nothing is lost, it's just not being yelled at you πŸ™ˆ
  • --max-jobs / -j number β€” sets the max number of build jobs Nix will run in parallel. say auto and it'll use however many CPUs the system has. the default comes from the max-jobs configuration setting, which itself defaults to 1. a higher number is useful on SMP systems or when you wanna exploit I/O latency, i.e. when your machine is just sitting there waiting and you're like "girl, do something" πŸ‘‘

setting it to 0 disallows building on the local machine β€” which is exactly what you want when builds should only happen on remote builders. main character remote-only era πŸ’…

  • --cores β€” sets the value of the NIX_BUILD_CORES environment variable in the invocation of builders. builders can use that variable however they please to control max parallelism. like, in Nixpkgs, if the derivation attribute enableParallelBuilding is set to true, the builder passes the -jN flag to GNU Make. defaults to the value of the cores configuration setting if it's set, or 1 otherwise. and the value 0 means the builder should use all available CPU cores in the system. go big or go home πŸ”₯
  • --max-silent-time β€” sets the max number of seconds a builder can go without producing any data on standard output or standard error. default comes from the max-silent-time configuration setting. 0 means no time-out β€” she can be silent forever, which is honestly a mood πŸŒ™
  • --timeout β€” sets the max number of seconds a builder can run. default comes from the timeout configuration setting. 0 means no timeout. go ahead, take your time, queen ⏳
  • --keep-going / -k β€” keeps going even when builds fail, to the greatest extent possible. so if building an input of some derivation fails, Nix will still build the other inputs β€” just not the derivation itself. without this option, Nix stops the moment any build fails (except for builds of substitutes) and might even kill builds that are in progress, in the case of parallel or distributed builds. brutal πŸ’€
  • --keep-failed / -K β€” says that if a build fails, the temporary directory where the build happened (usually somewhere in /tmp) should not be deleted. the path of the build directory gets printed as an informational message. forensic girlie behaviour, respect πŸ”
  • --fallback β€” whenever Nix tries to build a derivation where substitutes are known for each output path, but realising those output paths through the substitutes fails, it falls back on building the derivation itself.

the most common case where this is a lifesaver is when we've registered substitutes to do binary distribution from, say, a network repository. if the repo is down, realising the derivation will fail. with this option, Nix just builds the derivation instead. so installation from binaries falls back on installation from source ✨ this is not the default, because honestly it's generally not desirable for a transient failure in getting substitutes to trigger a whole build from source β€” with all the resource consumption that comes with it. like, no thank you? 😭

  • --readonly-mode β€” when this is on, no attempt is made to open the Nix database. most Nix operations do need database access, so those operations will just fail. it's giving "I'm just looking, I won't touch anything" and then everything breaks πŸ™ˆ
  • --arg name value β€” accepted by nix-env, nix-instantiate, nix-shell and nix-build. when evaluating Nix expressions, the evaluator will automatically try to call functions it encounters. it can automatically call functions where every argument has a default value (e.g. { argName ? defaultValue }: ...).

with --arg, you can also call functions that have arguments without a default value β€” or override a default value. so basically, if the evaluator encounters a function with an argument named name, it'll call it with value πŸ”₯

for instance, the top-level default.nix in Nixpkgs is actually a function:

{ # The system (e.g., `i686-linux') for which to build the packages.
system ? builtins.currentSystem
...
}: ...

so if you call this Nix expression (like when you do nix-env --install --attr pkgname), the function gets called automatically using the value builtins.currentSystem for the system argument. you can override that with --arg, e.g. nix-env --install --attr pkgname --arg system "i686-freebsd". (note that since the argument is a Nix string literal, you gotta escape the quotes, bestie β€” the shell is watching πŸ‘€)

  • --arg-from-file name path β€” passes the contents of the file at path as the argument name to Nix functions. file girlies rise πŸŽ€
  • --arg-from-stdin name β€” passes the contents of stdin as the argument name to Nix functions. pipe it in, we love a stream πŸ’œ
  • --argstr name value β€” like --arg, except the value isn't a Nix expression, it's a string. so instead of --arg system "i686-linux" (the outer quotes are there to keep the shell happy) you can just say --argstr system i686-linux. so much easier, no cap ✨
  • --attr / -A attrPath β€” selects an attribute from the top-level Nix expression being evaluated. (nix-env, nix-instantiate, nix-build and nix-shell only, bestie.)

the attribute path attrPath is a sequence of attribute names separated by dots. so like, given a top-level Nix expression e, the attribute path xorg.xorgserver would cause the expression e.xorg.xorgserver to be used. see nix-env --install for some concrete examples πŸ’…

and guess what β€” in addition to attribute names, you can also specify array indices! for instance, the attribute path foo.3.bar selects the bar attribute of the fourth element of the array in the foo attribute of the top-level expression. yes, 3 means the fourth one. programming is a nightmare but she's our nightmare 🫢

  • --eval-store store-url β€” the URL of the Nix store to use for evaluation, i.e. where to store derivations (.drv files) and the inputs referenced by them. keep your eval stuff separate, it's called boundaries 🌸
  • --expr / -E β€” interprets the command line arguments as a list of Nix expressions to be parsed and evaluated, instead of as a list of file names of Nix expressions. (nix-instantiate, nix-build and nix-shell only.)

for nix-shell, this option is commonly used to give you a shell in which you can build the packages returned by the expression. but if you want a shell that already contains the built packages, ready to use β€” pass your expression to the nix-shell --packages convenience flag instead. pick your fighter 😌

  • -I / --include path β€” adds an entry to the list of search paths used to resolve lookup paths. can be given multiple times, stack them up 🧚

paths added through -I take precedence over the nix-path configuration setting and the NIX_PATH environment variable. they go to the front of the line, periodt πŸ‘‘

  • --impure β€” allows access to mutable paths and repositories. living dangerously, we support it πŸ’…
  • --option name value β€” sets the Nix configuration option name to value. this overrides settings in the Nix configuration file (see nix.conf5). override queen 🌈
  • --repair β€” fixes corrupted or missing store paths by redownloading or rebuilding them. however β€” and listen closely β€” this is slow, because it requires computing a cryptographic hash of the contents of every path in the closure of the build. also note the warning under nix-store --repair-path. dramatic but true 😭
πŸ“Œ Note β€” see man nix.conf for overriding configuration settings with command line flags. iykyk ✨

πŸ’– COMMON ENVIRONMENT VARIABLES πŸŽ€

okay bestie, listen β€” basically most Nix commands read these environment variables when they run. That's the whole vibe. Here's the full list, no skips, no 🧒.

✨ Configuration environment variables ✨

These ones lowkey control how Nix loads its configuration. The configuration file documentation has the full deets, but here's the lineup:

  • NIX_CONF_DIR β€” overrides the system configuration directory. πŸ’…
  • NIX_USER_CONF_FILES β€” overrides the user configuration file locations.
  • NIX_CONFIG β€” gives Nix configuration settings inline. iconic.

🌸 Store setting environment variables 🌸

  • NIX_IGNORE_SYMLINK_STORE β€” so normally? The Nix store directory (typically /nix/store) is not allowed to contain any symlink components, and that's on purpose: it's to prevent "impure" builds. Here's why β€” builders sometimes "canonicalise" paths by resolving all symlink components. Which means builds on different machines (where /nix/store resolves to different locations) could totally yield different results. Usually that's not a problem, except when builds get deployed to machines where /nix/store resolves differently. If you're sure you're not gonna do that, you can set NIX_IGNORE_SYMLINK_STORE to 1.

Btw, if you're symlinking the Nix store so you can put it on a filesystem other than the root filesystem, on Linux you're better off using bind mount points, like:

$ mkdir /nix
$ mount -o bind /mnt/otherdisk/nix /nix

Go consult the mount 8 manual page for the details. 🫢

  • NIX_STORE_DIR β€” overrides the location of the Nix store. On Unix the default is /nix/store, set at compile time by the libstore:store-dir build option. On Windows there's no compile-time setting at all; the default is %PROGRAMDATA%\nix\store, figured out at runtime using the %PROGRAMDATA% Known Folder. Also, see the Store Types chapter β€” every store has a store setting that links back to this as its default.
  • NIX_LOG_DIR β€” overrides where the Nix log directory lives. On Unix the default is /nix/var/log/nix, set at compile time by the log-dir build option. On Windows there's no compile-time setting; the default is %PROGRAMDATA%\nix\log, determined at runtime using the %PROGRAMDATA% Known Folder. The Local Store, Local Daemon Store, and Experimental SSH Store with filesystem mounted all have per-store settings that override this.
  • NIX_STATE_DIR β€” overrides the location of the Nix state directory. On Unix the default is ${localstatedir}/nix, where localstatedir is a compile-time build option that defaults to /nix/var. On Windows there's no compile-time setting; the default is %PROGRAMDATA%\nix\state, determined at runtime using the %PROGRAMDATA% Known Folder. And same as above β€” the Local Store, Local Daemon Store, and Experimental SSH Store with filesystem mounted have per-store settings that override this.
  • NIX_DAEMON_SOCKET_PATH β€” overrides the path to the Unix domain socket used to talk to the Nix daemon. It defaults to daemon-socket/socket inside the state directory (that's NIX_STATE_DIR for you πŸ‘€). Check the Local Daemon Store documentation for the whole story on how the socket path gets resolved.
  • TMPDIR β€” use this directory to store temporary files. Specifically that includes temporary build directories, and those can eat up a substantial amount of disk space. The default is /tmp. 😭
  • NIX_REMOTE β€” overrides the store setting.

🧚 Nix language evaluator settings 🧚

  • NIX_SHOW_STATS β€” if you set it to 1, Nix prints some evaluation statistics, like the number of values allocated. cute little numbers ✨
  • NIX_COUNT_CALLS β€” if you set it to 1, Nix prints how often functions were called during Nix expression evaluation. Super useful for profiling your Nix expressions. πŸ“Š
  • GC_INITIAL_HEAP_SIZE β€” if Nix was configured to use the Boehm garbage collector, this variable sets the initial size of the heap, in bytes. Defaults to 384 MiB. Setting it low reduces memory consumption, but it'll increase runtime because of the overhead of garbage collection. pick your fighter πŸ’€
  • NIX_PATH β€” a colon-separated list of search path entries used to resolve lookup paths. This environment variable overrides the value of the nix-path configuration setting. You can also extend it using the -I option.
Example $ export NIX_PATH=/home/eelco/Dev:nixos-config=/etc/nixos

And here's the dramatic part: if NIX_PATH is set to an empty string, resolving search paths will always fail. periodt.

Example $ NIX_PATH= nix-instantiate --eval '<nixpkgs>' error: file 'nixpkgs' was not found in the Nix search path (add it using $NIX_PATH or -I)

πŸ‘‘ User Directories πŸ‘‘

Nix supports per-user configuration, state, and cache directories. These environment variables override where those directories live:

  • user configuration directory ([user configuration directory]{#user-conf-dir}): [NIX_CONFIG_HOME]{#env-NIXCONFIGHOME}
  • user state directory: [NIX_STATE_HOME]{#env-NIXSTATEHOME}
  • user cache directory: [NIX_CACHE_HOME]{#env-NIXCACHEHOME}

When none of those are set, the defaults depend on your platform:

  • On Unix, the XDG base directories: $XDG_CONFIG_HOME/nix, $XDG_STATE_HOME/nix, $XDG_CACHE_HOME/nix
  • On Windows, the Windows Known Folders: %APPDATA%\nix\config, %LOCALAPPDATA%\nix\state, %LOCALAPPDATA%\nix\cache

For backwards compatibility, legacy Nix commands (like nix-env, nix-channel) use dotfiles in $HOME instead of these directories, unless use-xdg-base-directories is enabled. The new Nix commands (experimental) use the proper directories by default. slay for them honestly πŸ¦‹

When use-xdg-base-directories is enabled, the configuration directory gets resolved like this:

  1. $NIX_CONFIG_HOME, if it's defined
  2. Otherwise, the platform default (e.g. $XDG_CONFIG_HOME/nix on Unix)

And likewise for the state and cache directories. same energy, different folders.

πŸ’« Miscellaneous environment variables πŸ’«

  • IN_NIX_SHELL β€” an indicator that tells you whether the current environment was set up by nix-shell. It can have the values pure or impure.

🌈 Appendix: OS-specific conventions 🌈

Quick heads up: this info isn't Nix-specific, it's just referenced up above. 🫢

πŸ’œ Unix: XDG Base Directories πŸ’œ

The XDG Base Directory Specification defines standard locations for user-specific configuration, state, and cache files on Unix systems. The environment variables in play are:

  • [XDG_CONFIG_HOME]{#env-XDGCONFIGHOME} (default ~/.config)
  • [XDG_STATE_HOME]{#env-XDGSTATEHOME} (default ~/.local/state)
  • [XDG_CACHE_HOME]{#env-XDGCACHEHOME} (default ~/.cache)
  • [XDG_CONFIG_DIRS]{#env-XDGCONFIGDIRS} (default /etc/xdg) β€” a colon-separated list of additional configuration base directories, searched after XDG_CONFIG_HOME

πŸ“ Windows: Known Folders πŸ“

On Windows, Known Folders provide standard locations for application data. The relevant ones are:

  • [%APPDATA%]{#env-APPDATA} β€” per-user roaming application data
  • [%LOCALAPPDATA%]{#env-LOCALAPPDATA} β€” per-user local application data
  • [%PROGRAMDATA%]{#env-PROGRAMDATA} β€” system-wide application data

πŸ”₯ Example πŸ”₯

watch it go:

$ nix-store --optimise
hashing files in `/nix/store/qhqx7l2f1kmwihc9bnxs7rc159hsxnf3-gcc-4.1.1'
...
541838819 bytes (516.74 MiB) freed by hard-linking 54143 files;
there are 114486 files with equal contents out of 215894 files in total

look at that byte count. it's giving main character energy fr fr πŸ’…


and that's a wrap, bestie!! πŸŽ€ that little footer line at the very bottom of the real page holds the source, the version and the date for this manual β€” it's the nix-store --optimise(1) one, and it's the official receipts. go forth and optimise, you absolute icon πŸ‘‘πŸ’–

πŸ“¦ where this page comes from