Create an AppImage, bundling a derivation and all its dependencies into a single-file executable. Like nix-bundle, but much faster and without any libc dependency.
To use this, you will need to have Nix available.
Then, run this via the nix bundle interface, replacing nixpkgs.hello
with the flake you want to build:
$ nix bundle --bundler github:ralismark/nix-appimage nixpkgs#hello
This produces hello-2.12.1-x86_64.AppImage
, which prints "Hello world!" when run:
$ ./hello-2.12.1-x86_64.AppImage
Hello, world!
If you get a main program ... does not exist
error, or want to specify a different binary to run, you can instead use the ./bundle
script:
$ ./bundle dnsutils /bin/dig # or ./bundle dnsutils dig
$ ./dig-x86_64.AppImage -v
DiG 9.18.14
- The produced file isn't a fully conforming AppImage. For example, it's missing the relevant .desktop file and icons -- this doesn't affect the running of bundled apps in any way, but might cause issues with showing up correctly in application launchers (e.g. rofi). Please open an issue if this is something you want.
- This requires Linux User Namespaces (i.e.
CAP_SYS_USER_NS
), which are available since Linux 3.8 (released in 2013). - Plain files in the root directory aren't visible to the bundled app.
If you package your program without including the loaders in the bundle and your program dlopens libvulkan / libGL, then the program has a high-chance (not 100%) of working on a non-NixOS system. The loader included in this repository also does some hacky things to make the binary run also in a NixOS and some other non-FHS systems (non 100% guarantee). The chance of success also depends on a how your binary is constructed.
This project wouldn't be possible without the groundwork already laid out in nix-bundle, and a lot here is inspired by what's done there.
The main benefit over nix-bundle's default arx format is that we don't need to unpack the files every time we start up. This significantly speeds up startup to the point that it's practically instant.
Thanks to using AppImageCrafers/appimage-runtime, the produced bundle doesn't depend on glibc, avoiding the issue described here and meaning it should be portable to more system. Since the AppImage format itself (specifically type 2 images) is essentially just the runtime binary concatenated with a squashfs file system, we also avoid unnecessary copies in the build step.
We do something similar to nix-user-chroot
, but instead only mount in the /nix
directory before running the entrypoint symlink.