Persistent packages on Steam Deck using Nix
95 comments
·February 9, 2025metadat
Cyph0n
To be honest, the naming is a bit confusing. Here is my understanding:
- Nix: build system and package manager (available on Linux and macOS)
- Nix: language used to define how to build packages
- nixpkgs: Nix package monorepo
- NixOS: Linux distro that is fully managed using Nix (language), has Nix (package manager) built-in, and is defined as part of nixpkgs
viraptor
It's this meme image, but actually
https://kagi.com/proxy/images?c=_m3km2RjA3G0qleowsZXHZb9NEn0...
bqmjjx0kac
Which itself is derived from the logic-defying diagram of the holy trinity: https://en.wikipedia.org/wiki/Trinity
squiggleblaz
Honestly I think you need to divide "Nix" up into two:[1] a language interpreter and the build system/sandbox. First nix interprets the expressions. It does that in your local context - so that, if it's configured to, it might read your .aws/credentials file to get access to resources stored in your S3 bucket. Once it's established what it needs to build, then the build system takes over and sets up a sandbox and runs bash scripts and other commands to produce output. I had conflated the two for some time and it caused my a variety of confusions that are resolved by observing the distinction.
(Also, I tend to think it's better to view NixOS as a tool for producing a linux distribution, which in many cases just happens to have an installbase of 1 - but that's not necessarily the case, and you could build your images with NixOS and deploy a dozen of them to aws.)
[1]: this was meant to be a joke, but it occurs to me that a person might think I missed that they had divided "Nix" up into two, the buildsystem and the language. But a language is not a command and doesn't do anything, so it can't possibly be an interpreter as well - and there could be and to some degree is multiple nix interpreters. So it is the first of the divisions of Nix that I sliced in two, and you end up with three Nixes: the buildsystem/sandbox; the main language interpreter; and the language.
soraminazuki
The language is also commonly referred to as Nix expressions or the Nix language.
Ericson2314
In fact, you can just download a statically build Nix binary and just start using it. The installer is IMO basically unnecessary for single user mode without root on Linux.
We should promote this more :)
kombine
https://github.com/DeterminateSystems/nix-installer I've had good experience with this installer if you have root access. I also installed nix on my work HPC cluster running Ubuntu via nix-portable.
bsimpson
For context, Determinate is a startup made of the Nix guy and some of the senior community members. They explicitly support the Steam Deck (and used it as a test case to create their installer).
asmor
Not just senior community members, DetSys is the company of the creator of nix.
This installer and the relationship between DetSys and Nix has also been subject to major criticism about conflict of interest between community interests and DetSys, since everyone agrees the official Nix installer has major issues. "Determinate Nix" (as DetSys calls the nix configured with their installer) also enables features that are the de-facto way to use Nix these days, but are disabled in the default distribution because of... let's say... commitment issues.
If you want a community run alternative, try Lix. They have a version of the DetSys installer too - and they actually cut releases of nix instead of building moats around it.
PerryStyle
Just out of curiosity, have you checked out Spack, https://github.com/spack/spack, which has a lot of HPC users. Support for mixing and matching both system and from source dependencies has been extremely useful in my work.
__MatrixMan__
I use it on macos for all of my dev environments. So instead of a readme that tells me to install tools X,Y and Z, direnv notices that I'm now in the project directory and it makes those tools available and then when I switch to a different project I end up with different sets of tools (pinned to the same versions on all my machines, tracked by git).
It's a bit more involved than homebrew, but you end up with a very precise definition of what your project depends on. This prevents all kinds of headaches re: Linux and Mac users depending on subtly different versions of grep or sed. Plus you can recreate the same environment in CI and Prod without having to define those dependencies separately.
Or you could, if your team was bought in. That's the hard part.
whatwhaaaaat
Just for a giggles, what projects do you work on that require such variation in tooling where something like this becomes worthwhile?
I always see these type of arguments for why nix is so great but it’s never been a pain point for me in 10+ languages and 20 years of development experience. I see your example of bash scripts but this can’t be all for writing scripts.
lmm
Scripts are the main place where it matters tbh - most language ecosystems have their own way of doing this stuff, if you can stay within the language you're fine. But if you (or your client) have a culture where people throw in awk/grep/sed then there's just no real alternative. Or if it's a polyglot project where you have three different languages (including shell) then you may not be able to use a single language package manager.
tstrimple
Not the OP, but I work in consulting. When I was still hands on keyboard, this would have been very helpful for the clients who don’t provide their own hardware or environment for us to use. I also do work for extremely large organizations who have literally dozens of different stacks accumulated over the decades.
In addition, I play with all sorts of open source tools and they often come with their own tool chains and expectations. Python version management in particular benefits a lot from this level of isolation. Instead of figuring out the different version management tools for each stack I use a higher order environment management tool in Nix.
Some others are solving these issues with containers, and that’s a part of the nix strategy as well.
__MatrixMan__
The most recent offenders were nodejs and kustomize used as part of a test flow orchestrated by a Makefile, run both locally and in CircleCI.
People will just install the latest version and start hacking away, and now you've got all this code that depends on that version. Backwards compatibility ain't perfect, so maybe several years later the original author doesn't work here anymore, so tests are breaking in subtle ways when you install what's the now latest version and there's nobody to ask what the "right" version is.
But since we're a culture that uses these tools (though I wish we weren't), this story has played out several times so different projects need different versions--you can't just discover the right one once and leave it installed in your system, you have to install the right one for your project and change it when you switch to a new project.
For the most part these are go projects, so even though there is language-specific dependency locking via go.mod and such, dependencies which aren't go libraries but which are nonetheless needed to work with the project (e.g. make) are left as an exercise to the reader. Make is pretty well behaved, I haven't had to do much version antics with it, but I wouldn't say that's the norm.
When I find one of these repos I put my archaeologist hat on and write a flake.nix to provide whatever the dependency is, and then I walk the version backwards until it starts working. That way next time I'm in that project I don't have to go through that exercise again.
To make matters worse, people often try to help by adding entries to the makefiles which download the correct version for that project, but some people have the newer arm chips and others are still on x86 so confusion of a new kind ensues. Of course it's easy to fix these scripts to detect the local architecture, but that's a whole extra step.
And then maybe you're trying to make this stuff work in CircleCI or somesuch, and you don't want the workflow to just be reaching out via https and blindly running whatever comes across the wire because who knows if it'll be the same thing tomorrow, so you add hash checks, but once you've got the hash checks and the architecture checks and you're checking the right hash for your architecture... we'll you've basically got a poor man's flake.lock at that point, might as well use the same nix config in both places rather than use homebrew or apt or whatever locally and then figure out how to do the same thing via circleci orbs in yaml and god forbid you have to do it in prod too so now there's a Dockerfile... Having a single source of truth for dependencies and using it everywhere is super handy.
That's work. Another example is in my personal projects. I use helix, so there's a .helix/languages.toml in my repo which defines the language servers that I'd like it to use for that project. But merely pointing helix at the language server isn't enough, it also has to be on the PATH. My older projects are using mypy, and my newer ones are using pyright (python type checkers).
Sure I guess I could just install both at the system level everywhere I go, but when I clone the project on a new machine I want to have everything work right away--I don't want to start coding and then wonder why my editor sucks and then go discover and install the right LSP and then resume coding. I'd end up with a smattering of different versions installed across all of my devices, even for the same project. If I find a bug which happens on this machine but not that one, I'd have a much harder time knowing where to start re: debugging it.
Finally there's this idea that maybe you don't even have to clone the repo, you can just reference the app you want to run from anywhere. I invoke some of my tools like:
nix run git+ssh://git@github.com/myorg/myrepo -- mycli --best-arg
Nix knows how to set up the environment for running the app (the one I have in mind is written in python, so a certain version of poetry is involved etc...) so I really don't need the caller to think about that environment at all. I like this because it decouples the orchestrator from the executor. So if I can manage to get something working locally with one of these commands, then I can go put the command someplace weird like in an Airflow DAG (kubernetes pod operator, NixOS image) and I have a pretty strong assurance that it'll work the same in the remote environment as it does locally.From the perspective of a nix user, these problems are all the same problem and they're everywhere and nix is the only thing that solves all of them at once. My feeling is that from the outside, they look like separate problems, and it's not clear just how many of them are solved by nix--so the juice doesn't appear to be worth the squeeze.
goosedragons
You can also do it with Guix in case you prefer Guile and more strict FOSSy-ness.
kombine
I'm playing with Guix and even made a dedicated installation. I find it more attractive than Nix (more sane language, shepherd service manager), but it lacks in diversity of packages and many of the ones I require are very stale.
gray_-_wolf
Patches are welcome :)
giancarlostoro
I guess peak Linux is to use Nix on Arch Linux for ultimate smugness.
bdhcuidbebe
That meme got old.
I use arch, btw, because its a solid rolling release and the AUR. Its the absolute best distro for a developer, theres really no competition.
otabdeveloper4
Last time I checked (a couple years ago) the version of nix in Arch repos shipped a subtly modified default configuration that rendered it broken, so yeah, a quintiessential Linux experience.
Rikudou
Installing nix from a package repository feels very wrong.
throwaway314155
Steam Deck runs Arch as it turns out.
rendaw
I've been using it for developing, but for non-headless stuff IIRC there's a lot of issues with opengl drivers and hardcoded X11 paths and stuff. I dropped a good chunk of time before giving up.
IshKebab
It's really 50 years of Unix's dumb practice of installing everything at absolute paths in `/usr` that has come home to roost. I wonder if Nix will finally make people write relocatable apps.
bronson
The opposite. Everything must be in /nix.
iamdbtoo
I'm currently experiencing this with a Tauri-based app. Nix has been great for us for local dev and service builds, but building an application inside of Nix that needs to run outside of it has been challenging to say the least.
phaer
Did you try https://github.com/numtide/nix-gl-host/ to help with nix & opengl drivers on non-nixos distros?
worble
Yeah, I just went through this process myself on steam deck and the fact it can't access opengl or vulkan natively makes anything that isn't terminal based a massive pain in the ass.
There is nixgl which you can wrap around any executable to make it work and it's got support in home-manager (https://nix-community.github.io/home-manager/options.xhtml#o...) but it's a huge annoyance having to wrap `config.lib.nixGL.wrap <package>` around everything you want to install.
ahoemora
It really depends on how you start your programs. If you wrap your compositor with nixgl then everything started through your compositior inherits the relevant env vars (LD_LIBRARY_PATH etc.) and you don't have to wrap the programs separately.
o11c
Last I checked, there was a major caveat to this - it mucks with your PATH in intrusive ways. So it's not "just try it", it's "switch to a frankenstein system and don't turn back"
saghm
I'm not sure about using Nix (the package manager) on other distros/macos, but I remember that when I tried out NixOS years ago, one of the things that struct me was just how little PATH stuff was needed. Literally the only thing in /usr/bin was `env`, and everything else was specific to each given package. My naive expectation would be that most of the stuff to be self-contained, like maybe a single script to `source` per package that could get set up as part of an invocation at the end of a shell config, and that worst case, switching back would be as simple as removing that invocation.
jamesgeck0
Nah.
- Normally, just deleting /nix gets you 95% of the way back to normal.
- If you want a bulletproof removal, the determinate systems Nix installer saves a file with a list of all the operations it made during installation so that it can be cleanly removed.
- If you want to stop home-manager from hooking into your shell without completely removing Nix, there's a separate uninstall command for that.
Rikudou
Hmm, didn't seem that way, I specifically did it the way I describe in the article to have it easily reversible, though I must admit it's just theoretical, I haven't tried uninstalling it.
tripdout
It just adds your Nix profile to your path.
bsimpson
> you can either run NixOS (which isn’t ideal on a Steam Deck)
I've actually been using NixOS on my Legion Go to give me the SteamOS experience while I wait for the official image from Valve [1].
I knew that Valve had whitelisted /nix, but seeing how the author explicitly loads Nix in Bash:
.nix-profile/etc/profile.d/nix.sh
makes me wonder how it works in game mode. Say that someone uses Nix to install a game like YARG that's not in the Steam store [2]. That will install the game to /nix/store and write an alias to the user's desktop. /home/deck is not immutable, so you could add the desktop file as a non-Steam game, and everything will work as expected, right?What are the boundaries between things that work everywhere, things that only work after you've loaded a bash profile (e.g. from a terminal), and things that only work in NixOS? What if a package wants to run at login? What if it uses its own systemd rules?
saghm
You definitely can easily run anything from outside Steam that you've added to as a "non-Steam game" from game mode like you describe; I use this a few mod management apps for various games I play, as well as for launching Battle.net on my Steam deck.
Not sure if I'm misunderstanding what you mean by systemd rules, but from what I understand, enabling a systemd service (either at the system or user level) is the most reliable way to make sure that something starts up in game mode as well as desktop mode. Because I find it useful to ssh into my Steam deck for a lot of things rather than trying to do it all via desktop mode (e.g. managing config files for Baldur's Gate 3 mods that aren't from the in-game mod installer), and I always turn off wifi on it whenever I leave my apartment with it to save battery, I enabled the sshd systemd service, and it's available even if I boot up directly into game mode. I haven't actually been able to find any other way outside of an enabled systemd service to make things start up automatically in game mode, which ended up being an issue for me when I wanted to autostart something through Wine that didn't have an option to avoid trying (and failing) to open a window.
bsimpson
So you can add Nix packages as non-Steam games and use Nix to setup persistent systemd rules/daemons, even though this isn't NixOS?
saghm
I haven't tried it personally, but from what I can tell, if you have a binary you can give a path to (and setting up env vars if needed in the "launch arguments"), you should be able to add it as a "non-Steam" game, and anything set up to start automatically via systemd seems to be properly started up in game mode, so I don't see why this wouldn't work!
Rikudou
Haven't tried adding Nix packages as non-Steam games, but you can use Home Manager to create user systemd rules.
jquaint
Love using Nix for retro gaming setups. Its great to bundle drivers, emulators, etc.
https://nixos.wiki/wiki/RetroArch https://nixos.wiki/wiki/Playstation2
bpye
Whilst nixos.wiki often shows up first in search results, you probably want wiki.nixos.org instead. There is some reasoning in the FAQ - https://wiki.nixos.org/wiki/FAQ#Why_is_there_a_new_wiki?_Wha...
craftkiller
This is great. Nix made compiling ship of harkinian (ocarina of time pc port), 2ship2harkinian (majora's mask pc port) and sm64ex (super mario 64 pc port) trivial on nixos but where I really want them is on my steam deck. Now I can.
dlcarrier
I've just been using Pacman and reinstalling a list of packages after every system update. The biggest problem is that it's easy to fill up the root partition, and I don't know if the updater could handle resizing it.
talldayo
This is actually a bit of a match made in heaven for Nix. The Steam Deck runs Arch with immutable root, which means most of the AUR packages won't entirely work. So you need a package manager which respects immutable root, supports atomic upgrades with Arch and has a package selection similar to the AUR. There are a few options, but the best one really is Nix: https://repology.org/repositories/statistics/newest
Given that package management on the Deck is traditionally handled with Flatpak, Nix seems like a great alternative for power users with storage to spare.
capitainenemo
Personally, I just mounted an overlay fs against the sdcard on /usr and installed what I wanted against their Arch snapshot and some standalone apps I needed.
Every few months I have to rerun an install script though, if I choose to upgrade to their latest release, since I don't want to risk doing that upgrade with the overlay in place.
But otherwise it's been working well for a couple of years.
Rikudou
I actually use both, flatpaks for GUI apps and Nix for various CLI tools, setting up my Deck like I described in the article was triggered by me being too lazy to check my local game server's IP on the server itself and wanted to use nmap for that.
Long story short, it would be faster to go check the computer physically. But it was more fun this way, even though I didn't have the time to play the game in the end.
dlcarrier
In my experience, Flatpak packages take far more resources than installing the same application with Pacman. Are Nix packages even larger?
otabdeveloper4
No, Nix installs each version of a library only once.
mhitza
VMs with Gnome Boxes also work nicely on the deck for power users. With KVM, measured via geekbench, the VM incurred only a 5% performance penalty.
sweeter
I run containers with podman as well as Waydroid for Android apps. I install novel reader applications or whatever and have them open in the background using TTS, while I play.
ksynwa
Does installing packages with nix pull in whole runtimes like flatpak does? Between flatpak, nix and the games the space usage could become a concern for me.
ilrwbwrkhv
I bought 20 Steam Decks recently to give to one of my teams. Will share this with them.
newfocogi
Now I'm curious. What kind of team are you running that they are receiving Steam Decks? Was this a reward or is your teams work related to it?
ZeWaka
Not the OP, but larger game companies definitely verify their games work as expected for all major platforms. It's definitely a extremely reasonable expense for a QA team - friends in the industry have said as much.
ilrwbwrkhv
Ya this was a reward. The deck is such a versatile device.
sweeter
Nix is great on the steam deck in so many ways. I use home manager just to install my general development environment, but at the same time there are some issues. like the sleep/suspend button will often cause the Nix Daemon socket to stop working, and you and you have to restart it, which can be kind of hard if you don't have access to SSH or whatever.
Rikudou
To be fair, I would be very afraid of the daemon mode on a Deck, that's why I went with the single user mode.
aussieguy1234
I'm on NixOS which of course uses nix.
I'm able to run steam games and have had no issues at all. Im using Lutris as the launcher, but you could easily use the official steam launcher (programs.steam.enable = true).
So you could technically get yourself a full gaming experience just with nix, without relying on the shipped steam client in SteamOS.
Rikudou
True, but SteamOS does much more than just provide the Steam client. I'd stick with SteamOS ona Deck.
TJSomething
Oh yeah, I've been doing this for a while. One of these days, I should switch to Home Manager.
colordrops
Would love if there was a Nix flake for setting up retro gaming. Last time I checked you had to install these complicated tools and set them up manually.
Rikudou
There's EmuDeck which does all of the work for you. There's also another newer package that does the same but I forgot the name. At least EmuDeck can be easily installed with a flatpak, no idea about the other one
asmor
EmuDeck is the more featureful one, but messy in a lot of places - and definitely not just a flatpak. I particularly hate how the ~/Emulation folder is full of absolute symlinks (even when creating sibling folder aliases!) to random places, so it can't be properly used with Syncthing unless you write your own ignore files and set up shares per emulator save directory. Their Windows version is also not exactly the same, so syncing media between a Windows machine and a Linux one is even more annoying.
RetroDeck bundles everything into a single flatpak and seems a lot saner, but is a lot newer.
colordrops
EmuDeck is exactly the package I was referring to that is a pain in the ass to setup.
I didn't realize you could install Nix on any Linux distro. It actually looks really straightforward:
https://forum.elivelinux.org/t/how-to-install-nix-packages-o...
I'm giving it a go now in the easily undoable single-user "no-daemon" mode.
Super excited how approachable this makes Nix, I've put this off for many years due to what turned out to be an incorrect assumption about the level of commitment!