close
Skip to content

gmodena/nix-flatpak

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

114 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

system build

nix-flatpak

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.

Versioning

We use Git tags and branches to manage versions:

  • 0.7.0 → Current stable release.
  • latest → Always points to the most recent stable version (0.7.0 as of now).
  • main → Unstable, development branch.

This project is released as a flake, and is published on flakehub and flakestry.

Background

This project was inspired by Martin Wimpress' Blending NixOS with Flathub for friends and family talk at NixCon 2023.

For implementation details and info about how this project came to be, see my Flatpaks The Nix Way talk at NixCon 2025. slides.

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 applications 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.

installation

Releases are tagged with semantic versioning. Versions below 1.0.0 are considered early, development, releases. Users can track a version by passing its release tag as ref

...
nix-flatpak.url = "github:gmodena/nix-flatpak/?ref=v0.7.0";
...

The latest tag will always point to the most recent release.

...
nix-flatpak.url = "github:gmodena/nix-flatpak/?ref=latest";
...

The main branch is considered unstable, and might break installs.

...
nix-flatpak.url = "github:gmodena/nix-flatpak/";
...

Manual installation

Flakes are the recommended and officially supported installation method, but under the hood nix-flatpak is just a Nix module.

nix-flatpak is not available in channels and needs to be manually downloaded and imported. Nixpkgs users can use the fetchFromGithub fetcher:

pkgs.fetchFromGitHub {
    owner = "gmodena";
    repo = "nix-flatpak";
    rev = "v0.7.0";
    hash = "sha256-7ZCulYUD9RmJIDULTRkGLSW1faMpDlPKcbWJLYHoXcs=";
  };

The package hash can be generated with:

nix-prefetch-github gmodena nix-flatpak --rev <rev>

Example:

let
  # Fetch nix-flatpak
  nix-flatpak = pkgs.fetchFromGitHub {
    owner = "gmodena";
    repo = "nix-flatpak";
    rev = "v0.7.0";
    hash = "sha256-7ZCulYUD9RmJIDULTRkGLSW1faMpDlPKcbWJLYHoXcs=";
  };
in
  imports = [
    # Import the nix-flatpak NixOS module and install applications system wide.
    # HomeManager users should import `${nix-flatpak}/modules/home-manager.nix`
    # where appropriate.
    "${nix-flatpak}/modules/nixos.nix"
  ];
  # ... your config

  # Configure nix-flatpak
  services.flatpak = {
    enable = true;
    packages = [
      "org.mozilla.firefox"
    ];
  };

A minimal config that can be built and tested in a NixOS VM (via nix-build) can be found at configuration.nix.

Starter config example

You can find an example configuration in testing-base/flatpak.nix.

Getting Started

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.

Notes on HomeManager

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.

Remotes

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";
}];

Packages

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

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:

  1. If the package does not specify an origin, use the remote name suggested by the flatpakref in SuggestRemoteName.
  2. If the flatpakref does not suggest a remote name, sanitize the flatpakref Name key with the same algo flatpak implements in create_origin_remote_config().

Flatpak bundles

Bundle files (.flatpak) can be installed directly by pointing bundle at a URI and providing a matching sha256:

services.flatpak.packages = [
  rec {
    appId = "<appId>";
    sha256 = "<hash>";
    bundle = "${pkgs.fetchurl {
      url = "<bundle-uri>";
      inherit sha256;
    }}";
  }
];

You can also install a local bundle from disk:

services.flatpak.packages = [
  {
    bundle = "file:///path/to/local/app.flatpak";
    appId = "<appId>";
    sha256 = "<hash>";
  }
];
Unmanaged packages and remotes

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.

Updates

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.

Storage

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:

  1. I want to track the latest version of all installed applications.
  2. I am happy to trade network for storage.

YMMV.

If you want an alternative approach with transactional package installation, declarative-flatpak might be a better fit.

Overrides

Flatpak overrides allow you to modify application permissions and environment variables. nix-flatpak provides two ways to manage overrides: inline settings and external files.

WARNING: using these settings will overwrite system/user flatpak override files and could cause data loss. Backup your files before enabling .settings and/or .files.

Inline configuration

Use services.flatpak.overrides.settings to declare overrides directly in your nix configuration:

{
  services.flatpak.overrides.settings = {
    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
  };
}

Backwards compatibility: The legacy (nix-flatpak <= 0.7) format services.flatpak.overrides = { "app.id" = {...}; } (without the .settings wrapper) is still supported, but will be removed in the future.

Eexternal override files

Use services.flatpak.overrides.files to load overrides from external INI files. This is useful for sharing override configurations across machines, managing complex overrides separately from your nix configuration and/or using existing Flatpak override files. See [https://github.com/gmodena/nix-flatpak/issues/82][!82].

The file name must match the application ID (e.g., com.visualstudio.code). Files should be in standard Flatpak override INI format:

[Context]
sockets=wayland;!x11;

[Environment]
GTK_THEME=Adwaita:dark

Combining settings and files

When both settings and files are specified for the same application, they are merged. Values from settings take precedence over values from files, and both are merged with any externally applied overrides already on disk.

{
  services.flatpak.overrides = {
    # Base configuration from file
    files = [ "/path/to/overrides.d/com.visualstudio.code" ];

    # Additional settings merged on top
    settings."com.visualstudio.code".Context.sockets = ["gpg-agent"];
  };
}

Write mode

The writeMode option controls how nix-flatpak writes override files to disk. It accepts two values:

  • "merge" (default): at activation time, existing override files on disk are read and merged with the nix-managed settings. Direct user edits to keys not declared in nix are preserved across generations.
  • "replace": the complete override file for each application is computed at evaluation time as a pure store derivation. At activation time the precomputed file is copied to the overrides directory. nix-flatpak fully owns the file. Any direct user edits are overwritten on the next activation.
{
  services.flatpak.overrides.writeMode = "merge";   # default
}
Evaluation

When overrides.files contains plain string paths (paths outside the Nix store), nix-flatpak must read them from the filesystem at evaluation time, which is an impure operation. This applies to both write modes, because the state file always parses overrides.files at eval time regardless of writeMode.

Such configurations require passing --impure to nixos-rebuild:

{
  services.flatpak.overrides = {
    files = [
      "/home/user/dotfiles/overrides/com.visualstudio.code" 
    ];
  };
}
sudo nixos-rebuild switch --impure

To avoid --impure, use Nix path literals instead of strings for overrides.files. Path literals are copied into the Nix store during evaluation, making the entire configuration reproducible:

{
  services.flatpak.overrides = {
    files = [
      ./overrides/com.visualstudio.code
      ./overrides/org.gnome.Terminal
    ];
  };
}

With writeMode = "replace" and store-path files, the merged override content for each application is fully determined at evaluation time. No reading of on-disk override files occurs at activation. This is the most reproducible configuration.

Note: writeMode = "replace" with only settings (no files) is always pure and never requires --impure.

Deleting orphaned override files

Bugs of incorrect use of this option can result in data loss. Make sure your overrides are backed up before enabling this option.

By default, when you remove an override from your nix configuration, the corresponding file in the flatpak overrides directory is preserved on disk. This behaviour is controlled by the pruneUnmanagedOverrides option:

{
  services.flatpak.overrides.pruneUnmanagedOverrides = false; # Default
}

When pruneUnmanagedOverrides = true, nix-flatpak scans the actual overrides directory and removes any files that are not declared in the current configuration (either in settings or files). This ensures a clean state where only managed overrides exist.

If you previously had pruneUnmanagedOverrides = false, switching to pruneUnmanagedOverrides = true will delete all override files removed from the current config that were present in the previous generation. If override files accumulated over previous generations, a manual cleanup of all unmanaged files will be necessary.

Downgrading to a release prior to v2 state format

nix-flatpak uses an internal state file to track managed overrides across activations. Releases > 0.7.0 support overrides.settings and overrides.files write a v2 state file. If you downgrade to an older release that only understands the v1 flat overrides format, the older release will misinterpret its meta-keys (settings, files, _fileSettings, pruneUnmanagedOverrides, writeMode) as Flatpak app ids.

On the first activation after the downgrade, the older release will create spurious override files with those names in your flatpak overrides directory (/var/lib/flatpak/overrides or ~/.local/share/flatpak/overrides). These files have no effect (Flatpak ignores filenames that are not valid reverse-domain app IDs) but they are left on disk as clutter.

Your real app override files are not affected. To clean up the stray files, run:

# For a user (home-manager) installation
for name in settings files _fileSettings pruneUnmanagedOverrides writeMode; do
  rm -f "${XDG_DATA_HOME:-$HOME/.local/share}/flatpak/overrides/$name"
done

# For a system (NixOS) installation
for name in settings files _fileSettings pruneUnmanagedOverrides writeMode; do
  sudo rm -f "/var/lib/flatpak/overrides/$name"
done

Systemd unit retry on error

On flaky network connections the nix-flatpak installer script may fail.

The restartOnFailure option controls the behavior of the flatpak-managed-install service when it encounters a failure. As of 0.6.0 it is enabled by default, and wraps systemd APIs. It's configuration can be modified by setting:

restartOnFailure = {
  enable = true;
  restartDelay = "60s";
  exponentialBackoff = {
    enable = false;
    steps = 10;
    maxDelay = "1h";
  };
};

See module/options.nix and systemd's own documentation for more details.

Known issues

A couple of things to be aware of when working with nix-flatpak.

Infinite recursion in home-manager imports

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.

Q&A and support

For further support questions and common issues on how to integrate and set up nix-flatpak on your system, please consult the Q&A discussions page.

About

Install flatpaks declaratively

Topics

Resources

License

Stars

Watchers

Forks

Contributors