Declarative flatpak manager for NixOS inspired by declarative-flatpak and nix-darwin's homebrew module. NixOs and home-manager modules are provided for system wide or user flatpaks installation.
This repository contains experimental code inspired by Martin Wimpress' Blending NixOS with Flathub for friends and family talk at NixCon 2023. I like the idea of managing applications the same way I do with homebrew on nix-darwin.
nix-flatpak
follows a convergent mode approach to package management (described in this thread):
the target system state description is not exhaustive, and there's room for divergence across builds
and rollbacks.
For a number of desktop application I want to be able to track the latest version, or allow them to auto update.
For such applications, a convergent approach is a reasonable tradeoff wrt system reproducibility. YMMV.
Flatpak applications are installed by systemd oneshot service triggered at system activation. Depending on the number of applications to install, this could increase activation time significantly.
This project is released as a flake, and is published on flakehub.
Releases are tagged with semantic versioning. Versions below 1.0.0
are considered early, development, releases.
Users can track a version by passing its tag as ref
...
nix-flatpak.url = "github:gmodena/nix-flatpak/?ref=v0.4.1";
...
The main
branch is considered unstable, and might break installs.
Enable flatpak in configuration.nix
:
services.flatpak.enable = true;
Import the module (nixosModules.nix-flatpak
or homeManagerModules.nix-flatpak
).
Using flake, installing nix-flatpak
as a NixOs module would look something like this:
{
inputs = {
# ...
nix-flatpak.url = "github:gmodena/nix-flatpak"; # unstable branch. Use github:gmodena/nix-flatpak/?ref=<tag> to pin releases.
};
outputs = { nix-flatpak, ... }: {
nixosConfigurations.<host> = nixpkgs.lib.nixosSystem {
modules = [
nix-flatpak.nixosModules.nix-flatpak
./configuration.nix
];
};
};
}
See flake.nix in testing-base for examples of setting up nix-flatpak
as a NixOs and HomeManager module.
Depending on how config and inputs are derived homeManagerModules
import can be flaky. Here's an example of how homeManagerModules
is imported on my nixos systems config in modules/home-manager/desktop/nixos/default.nix. flake-inputs
is a special extra arg set in the repo flake.nix
mkNixosConfiguration.
By default nix-flatpak
will add the flathub remote. Remotes can be manually
configured via the services.flatpak.remotes
option:
services.flatpak.remotes = [{
name = "flathub-beta"; location = "https://flathub.org/beta-repo/flathub-beta.flatpakrepo";
}];
Note that this declaration will override the default remote config value (flathub
).
If you want to keep using flathub
, you should explicitly declare it in the
services.flatpak.remotes
option.
Alternatively, it is possible to merge declared remotes with the default one with lib.mkDefaultOption
.
services.flatpak.remotes = lib.mkOptionDefault [{
name = "flathub-beta";
location = "https://flathub.org/beta-repo/flathub-beta.flatpakrepo";
}];
Declare packages to install with:
services.flatpak.packages = [
{ appId = "com.brave.Browser"; origin = "flathub"; }
"com.obsproject.Studio"
"im.riot.Riot"
];
You can pin a specific commit setting commit=<hash>
attribute.
Rebuild your system (or home-manager) for changes to take place.
Flatpakref files can be installed by setting the flatpakref
attribute to :
services.flatpak.packages = [
{ flatpakref = "<uri>"; sha256="<hash>"; }
];
A sha256
hash is required for the flatpakref file. This can be generated with nix-prefetch-url <uri>
.
Omitting the sha256
attribute will require an impure
evaluation of the flake.
When installing an application from a flatpakref
, the application remote will be determined as follows:
- If the packageOptions contains an origin, use that as the label for the remote URL.
- If the package does not specify an origin, use the remote name suggested by the flatpakref (SuggestRemoteName).
- If neither the package sets an origin nor the flatpakref suggests a remote name, sanitize the application Name.
By default nix-flatpak
will only manage (install/uninstall/update) packages declared in the
services.flatpak.packages
and repositories declared in services.flatpak.remotes
.
Flatpak packages and repositories installed by the command line of app stores won't be affected.
Set services.flatpak.uninstallUnmanaged = true
to alter this behaviour, and have nix-flatpak
manage the
lifecycle of all flatpaks packages and repositories.
Note that services.flatpak.uninstallUnmanaged
will only affect a given system
of user
installation
target. If nix-flatpak
is installed as a HomeManager module all packages/remotes will be managed
in a user
installation. Packages/remotes installed system-wide won't be affected
by services.flatpak.uninstallUnmanaged
.
Similarly, when nix-flatpak
is installed as a NixOs module, only system-wide config will
be affected.
Set
services.flatpak.update.onActivation = true;
to enable updates at system activation. The default is false
so that repeated invocations of nixos-rebuild switch
are idempotent. Applications
pinned to a specific commit hash will not be updated.
Periodic updates can be enabled by setting:
services.flatpak.update.auto = {
enable = true;
onCalendar = "weekly"; # Default value
};
Auto updates trigger on system activation.
Under the hood, updates are scheduled by realtime systemd timers. onCalendar
accepts systemd's
update.auto.onCalendar
expressions. Timers are persisted across sleep / resume cycles.
See https://wiki.archlinux.org/title/systemd/Timers for more information.
Flatpaks are stored out of nix store at /var/lib/flatpak
and ${HOME}/.local/share/flatpak/
for system
(nixosModules
) and user (homeManagerModules
) installation respectively.
Flatpaks installation are not generational: upon a system rebuild and rollbacks, changes in packages declaration
will result in downloading applications anew.
Keeping flatpaks and nix store orthogonal is an explicit design choice, dictate by my use cases:
- I want to track the latest version of all installed applications.
- I am happy to trade network for storage.
YMMV.
If you need generational builds, declarative-flatpak might be a better fit.
Package overrides can be declared via services.flatpak.overrides
. Following is a usage example:
{
services.flatpak.overrides = {
global = {
# Force Wayland by default
Context.sockets = ["wayland" "!x11" "!fallback-x11"];
Environment = {
# Fix un-themed cursor in some Wayland apps
XCURSOR_PATH = "/run/host/user-share/icons:/run/host/share/icons";
# Force correct theme for some GTK apps
GTK_THEME = "Adwaita:dark";
};
};
"com.visualstudio.code".Context = {
filesystems = [
"xdg-config/git:ro" # Expose user Git config
"/run/current-system/sw/bin:ro" # Expose NixOS managed software
];
sockets = [
"gpg-agent" # Expose GPG agent
"pcsc" # Expose smart cards (i.e. YubiKey)
];
};
"org.onlyoffice.desktopeditors".Context.sockets = ["x11"]; # No Wayland support
};
}
A couple of things to be aware of when working with nix-flatpak
.
Users have reported an infinite recursion stacktrace when importing an home-manager module outside of where home-manager itself was imported.
To work around this issue, you should avoid nesting home-manager modules. This means that when you are structuring your configuration, make sure that you do not have home-manager modules imported within each other in a way that could lead to circular imports.
You can follow the discussions and updates on issue #25 to stay informed about any resolutions or workarounds.