I have owned the Affinity V2 Universal License for a while, and I still had the complete Windows installations for Photo 2, Designer 2, and Publisher 2 on one of the Windows drive.

They were surprisingly portable on Windows. I had previously reinstalled Windows 11, opened the applications from their old location, entered my license details, and moved on using them.

Linux was the more interesting question.

Could I run Affinity Photo 2 properly on NixOS without turning the machine into a science project of Wine-prefix six months later?

The answer, as of Affinity V2 2.6.5, is yes. It is not native Linux software, and one acceleration feature still remains unavailable, but the actual editing workflow worked:

  • Affinity Photo launched repeatedly;
  • my V2 Universal License activated from the built-in account page;
  • existing documents opened;
  • PSD, PNG, and WebP exports worked;
  • the NVIDIA GPU appeared as the renderer;
  • preferences and UI scaling persisted between launches.

This is how I tested it, avoided downloading several gigabytes of installers again, and then moved it into my declarative NixOS configuration.

Warning

mrshmllow/affinity-nix is community packaging. It is not maintained or supported by Affinity, Serif, or Canva. Affinity under Wine is also not perfect, so keep a known-good Windows path for work you absolutely cannot afford to surprise you.

I also did something similar with the process of installing ChatGPT+Codex but this one is a bit more time-consuming and complex.

TLDR;

The short version is:

  1. Run Affinity Photo temporarily with nix run.
  2. Allow the unfree package for that command.
  3. If the upstream installer downloads are slow, download the official V2 2.6.5 MSI/EXE installers from your Affinity account.
  4. Verify that they match the hashes expected by affinity-nix.
  5. Import them into the Nix store instead of manually copying anything into /nix/store.
  6. Launch Photo, set Wine to 144 DPI if the interface is tiny, and activate the license from My Account.
  7. Once the trial works, pin affinity-nix in flake.lock and declare the applications normally.
  8. Back up ~/.local/share/affinity/, but never commit it or the proprietary installers to Git.

The first test command is:

NIXPKGS_ALLOW_UNFREE=1 nix run --impure \
  github:mrshmllow/affinity-nix#affinity-photo

Do not be surprised if the first build is large and serverly time consuming. More on this, later in this article.

Why I used affinity-nix

I already had Bottles installed, and manually creating a Wine prefix was still an option. But affinity-nix fits NixOS better.

It builds the Wine environment and dependencies through Nix, then mounts an overlay at runtime so user preferences remain writable. The immutable package and mutable state stay separate instead of slowly becoming one unrepeatable prefix.

The V2 packages are:

affinity-photo
affinity-designer
affinity-publisher

There is one slightly surprising detail: the three V2 applications share the same prepared prefix. Running only affinity-photo may cause Photo, Designer, and Publisher sources to be fetched and extracted.

That confused me at first when the terminal said it was downloading Publisher while I had asked for Photo. It was not installing random software behind my back. It was preparing the shared V2 environment used by all three launchers.

flowchart TB
    A["🔒 flake.lock"]
    B["📦 affinity-nix + Wine dependencies"]
    C["🧱 Shared Affinity V2 prefix"]
    D["🖼️ Photo 2"]
    E["✒️ Designer 2"]
    F["📚 Publisher 2"]
    G["💾 ~/.local/share/affinity/"]
    H["🗄️ Backrest"]

    A --> B --> C
    C --> D
    C --> E
    C --> F
    G <-->|"preferences, activation, Wine overlay"| C
    G --> H

First run: allow the unfree package

Running the simple command directly gave me this error:

Refusing to evaluate package 'affinity-photo-2.6.5'
because it has an unfree license ('unfree')

For a one-off flake command, use the temporary environment variable and --impure together:

NIXPKGS_ALLOW_UNFREE=1 nix run --impure \
  github:mrshmllow/affinity-nix#affinity-photo

--impure is required here because the flake must be allowed to read NIXPKGS_ALLOW_UNFREE from the environment.

This does not permanently change the NixOS configuration.

Why the first run can take forever

The project provides an optional binary cache at cache.forall.systems. That cache can provide Wine, helper tools, and other non-proprietary build results.

It deliberately does not cache the proprietary Affinity archives.

That is what this note in the upstream README means:

This repo does not attempt to redistribute affinity archives.
Any instance of caching Canva IP should be reported as a bug.

The Nix expressions still tell the local machine where to fetch the required Affinity installers and which hashes to expect. The installers are downloaded and verified on your machine; they are not served from the project’s binary cache.

My initial run spent a very long time downloading (I stopped the download at 97 minutes) the three V2 2.6.5 installers from Archive.org. Archive.org downloads are super slow. I already had the exact official files from my Affinity v2 account, so downloading them again was pointless.

There is a cleaner route.

Use official local installers instead of downloading them again

Download the final Affinity V2 Windows MSI/EXE installers from your own Affinity account. For me it took me 32 seconds to download all 3 of them.

For the current V2 package, the expected filenames are:

affinity-photo-msi-2.6.5.exe
affinity-designer-msi-2.6.5.exe
affinity-publisher-msi-2.6.5.exe

I keep my recovery copies here:

/home/rabin/installers/affinity-v2/

Use whatever protected path makes sense on your machine. Do not put proprietary installers inside a public Git repository.

Verify the files first

Check each file with Nix:

nix hash file --type sha256 --sri \
  /home/rabin/installers/affinity-v2/affinity-photo-msi-2.6.5.exe

nix hash file --type sha256 --sri \
  /home/rabin/installers/affinity-v2/affinity-designer-msi-2.6.5.exe

nix hash file --type sha256 --sri \
  /home/rabin/installers/affinity-v2/affinity-publisher-msi-2.6.5.exe

At the revision used in this guide, affinity-nix expects:

Photo 2.6.5
sha256-waCX33rWVzZ8AYZWmv2EOqS6ikT6p7s9qRJ+8rDo6Wk=

Designer 2.6.5
sha256-b5K1FtsCWCjyn/NC4trB0g9Wv+AfLoDWgaZK2ZGXW0w=

Publisher 2.6.5
sha256-76ikkAnbAghaSU5YLYLxXiHfAuqVfoEcQK16rHd6+7A=

All three of my account downloads matched byte for byte.

Important

Do not rename a different release to 2.6.5 and assume it is close enough. The contents must match the expected cryptographic hash. If upstream changes its package sources later, inspect the current packages/sources.nix in the pinned affinity-nix revision rather than copying these hashes blindly.

Import the matching files correctly

Never copy files directly into /nix/store.

Add the verified installers through Nix (change the /home/rabin/installers/affinity-v2/ to the correct location):

nix store add --mode flat --hash-algo sha256 \
  --name affinity-photo-msi-2.6.5.exe \
  /home/rabin/installers/affinity-v2/affinity-photo-msi-2.6.5.exe

nix store add --mode flat --hash-algo sha256 \
  --name affinity-designer-msi-2.6.5.exe \
  /home/rabin/installers/affinity-v2/affinity-designer-msi-2.6.5.exe

nix store add --mode flat --hash-algo sha256 \
  --name affinity-publisher-msi-2.6.5.exe \
  /home/rabin/installers/affinity-v2/affinity-publisher-msi-2.6.5.exe

Nix calculates the content-addressed store paths. Because the names and contents match the fixed-output sources expected by affinity-nix, the next build reuses them.

After importing the files, I ran the original test again:

NIXPKGS_ALLOW_UNFREE=1 nix run --impure \
  github:mrshmllow/affinity-nix#affinity-photo

The installer download stage disappeared, and the application started almost immediately because the remaining prefix work had already completed.

Fix the tiny Wine interface

Affinity launched, but its menus and interface were much too small on my 1440p displays.

Affinity V2 does not expose a useful application-level UI scaling control. The correct place to fix this was Wine DPI.

Close Affinity, then open winecfg through the same package wrapper:

NIXPKGS_ALLOW_UNFREE=1 nix run --impure \
  github:mrshmllow/affinity-nix#affinity-photo \
  -- wine winecfg

Open Graphics, change Screen resolution, then apply the setting.

My displays use 1.2x compositor scaling. I tried 120 DPI first because the arithmetic looked sensible. It was still too small. 144 DPI was the setting that actually looked correct.

Use your eyes, not just the equation.

Wine configuration graphics tab, I set mine to 144dpi

The DPI choice persisted across multiple launches because the writable Wine state lives under:

~/.local/share/affinity/

Activate the V2 license

Affinity did not force a license prompt during the initial launches. I opened My Account, signed in with my Affinity account, and activated the V2 Universal License there.

The account page then reported that the license was active and would not expire.

I closed and reopened Photo several times. The activation and preferences persisted.

Affinity v2 licence activated on NixOS wine

Warning

~/.local/share/affinity/ may contain account, activation, registry, and application state. Back it up as sensitive mutable data. Do not commit it to Git, paste its registry files into an issue, or casually share the entire directory.

NVIDIA works, but OpenCL does not

Affinity detected my NVIDIA RTX 3080 Ti as the renderer. Canvas interaction, opening documents, and exports all worked.

The Hardware Acceleration option could not be enabled, though.

This is not a missing CUDA checkbox. Affinity V2’s Windows compute-acceleration path uses OpenCL, not CUDA. The package provides Vulkan/VKD3D for the Direct3D rendering path, but the current Wine environment does not expose a compatible Windows OpenCL device to Affinity.

In practical terms:

  • GPU-backed display rendering works;
  • some compute-heavy operations fall back to the CPU;
  • OpenCL acceleration remains unavailable;
  • PSD, PNG, and WebP exports still worked in my tests.

Note

I left OpenCL disabled (it can’t be enabled anyway).

Affinity v2 Photos opened files

Declare Affinity V2 in the NixOS flake

Once the temporary test worked, I moved it into the actual NixOS configuration.

My configuration keeps shared desktop packages in packages.nix and passes external flake inputs through specialArgs. Adapt the file layout to your own configuration; there is no prize for reorganizing a working flake just to copy mine exactly.

Add the flake input

flake.nix
{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";

    affinity-nix.url = "github:mrshmllow/affinity-nix";
  };

  outputs = {
    nixpkgs,
    affinity-nix,
    ...
  }:
  {
    nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";

      specialArgs = {
        inherit affinity-nix;
      };

      modules = [
        ./configuration.nix
      ];
    };
  };
}

I did not force the external flake’s Nixpkgs input to follow mine. The revision and its transitive inputs stay visible and pinned in flake.lock.

Apply the overlay and add the launchers

My package module receives affinity-nix, applies its overlay, and declares the three V2 applications:

packages.nix
{ pkgs, affinity-nix, ... }:

{
  nixpkgs.overlays = [ affinity-nix.overlays.default ];

  environment.systemPackages = with pkgs; [
    # Other applications

    affinity-photo
    affinity-designer
    affinity-publisher
  ];
}

All three launchers use the same prepared V2 prefix, so declaring the suite does not create three completely independent Wine environments.

If you only want Photo, this is also valid:

environment.systemPackages = with pkgs; [
  affinity-photo
];

The shared prefix still contains the V2 application sources used by upstream; this only controls which launcher package enters the system environment.

Allow unfree packages declaratively

My system already had this setting:

configuration.nix
nixpkgs.config.allowUnfree = true;

After Affinity becomes part of the NixOS configuration, I no longer need NIXPKGS_ALLOW_UNFREE=1 for normal launches.

Pin and test it

Update the lock file:

nix flake update affinity-nix

Then check and test the configuration:

nix flake check --no-build
sudo nixos-rebuild test --flake .#nixos
sudo nixos-rebuild switch --flake .#nixos

Time Consuming

During the initial build - this can take a long time. For my i7 12th gen 20 core processor and NVME drive, it still took 2 hours 7 minutes. Depending on your CPU/RAM/Disk speed config - this can take much longer. Nix will be compiling the custom patched wine-wow64 required by Affinity.

Go out, touch the grass or something.

The first declarative build can still be large and time consuming. Applying the overlay builds the package against the Nixpkgs package set used by the system configuration, so do not start it five minutes before shutting down the machine and then act surprised.

The imported fixed-output Affinity installers remain reusable. In my dry run, Nix planned the Wine and runner build but did not plan another download of the three proprietary installers.

Affinity Designer 2 Start screen nixos wine

What belongs in Git and what belongs in backup

This boundary is important, more than the final package list.

Git

I keep these in the NixOS repository:

  • the affinity-nix flake input;
  • flake.lock;
  • the overlay declaration;
  • the selected application packages;
  • installer filenames and expected hashes;
  • recovery instructions.

Backrest or another encrypted backup

I back up:

/home/rabin/.local/share/affinity/
/home/rabin/installers/affinity-v2/

The first path contains mutable Wine, preference, and activation state. The second contains my official proprietary recovery media.

Neither belongs in Git.

The Nix store is also not a backup strategy. Garbage collection can remove paths that are no longer rooted. Keep the official installers somewhere you control if you want recovery to remain possible after an upstream archive disappears.

Updating or removing it later

To update only the package source:

nix flake update affinity-nix

Review the lock-file change and test again. A newer upstream revision may change expected installers, Wine patches, or state revisions.

To remove Affinity declaratively:

  1. remove the packages and overlay;
  2. remove the flake input if nothing else uses it;
  3. update the lock file;
  4. rebuild the system;
  5. inspect ~/.local/share/affinity/ before deleting anything;
  6. run normal Nix garbage collection only when you no longer need the previous closure.

Do not delete /nix/store paths manually. Nix owns that tree.

What about Affinity V3?

The repository also packages Canva’s unified Affinity V3 application as:

affinity-v3

It uses separate mutable state under:

~/.local/share/affinity-v3/

I am transitioning toward V3 through a Canva account, but I deliberately kept that as a separate future test. The working, perpetual V2 Universal License is too useful as a fallback to mix both experiments into the same checkpoint.

One thing at a time. NixOS is very good at reproducibility; I do not need to test my ability to create parallel problems.

Final result

Affinity Photo 2 is now genuinely useful on my NixOS workstation, not merely able to draw a window.

The practical result is:

  • repeatable Wine packaging through Nix;
  • official V2 installer files reused locally;
  • no manual writing inside /nix/store;
  • persistent 144 DPI scaling;
  • an activated V2 Universal License;
  • working PSD, PNG, and WebP exports;
  • NVIDIA rendering through Vulkan/VKD3D;
  • mutable account and preference state protected separately from Git.

OpenCL compute acceleration remains the main limitation. For my current Photo workflow, it did not make an issue, yet!

That is a much better outcome than I expected from a Windows-only creative suite on NixOS.