Skip to content

Instantly share code, notes, and snippets.

@Jabb0
Last active November 16, 2025 19:53
Show Gist options
  • Select an option

  • Save Jabb0/1b7ad92e8ab3065ac999c21edc23311f to your computer and use it in GitHub Desktop.

Select an option

Save Jabb0/1b7ad92e8ab3065ac999c21edc23311f to your computer and use it in GitHub Desktop.
Fixing macos spotlight and alfred indexing of home manager apps.

I spent two days on this, because I did not want to:

  1. Copy the apps
  2. Use trampolines.
  3. Aliases (because they do not show up as applications).
  4. Wrapper scripts (because I got weird rosetta prompts).

The issues seems to be the symlinks.

What worked for me was a hybrid approach. I copy the Info.plist and the icon and symlink the rest.

Claude.ai was friendly enough to give me some code for this that worked (modulo some manual fixes).

{ pkgs, config, lib, ... }:
{
imports = [
./macos-apps-fix.nix
];
}
{ pkgs, config, lib, ... }:
{
# Need to copy the apps because otherwise spotlight does not find them.
home.activation = {
copyNixApps = lib.hm.dag.entryAfter ["linkGeneration"] ''
# Create directory for the applications
mkdir -p "$HOME/Applications/Nix-Apps"
# Remove old entries
rm -rf "$HOME/Applications/Nix-Apps"/*
# Get the target of the symlink
NIXAPPS=$(readlink -f "$HOME/.nix-profile/Applications")
# For each application
for app_source in "$NIXAPPS"/*; do
if [ -d "$app_source" ] || [ -L "$app_source" ]; then
appname=$(basename "$app_source")
target="$HOME/Applications/Nix-Apps/$appname"
# Create the basic structure
mkdir -p "$target"
mkdir -p "$target/Contents"
# Copy the Info.plist file
if [ -f "$app_source/Contents/Info.plist" ]; then
mkdir -p "$target/Contents"
cp -f "$app_source/Contents/Info.plist" "$target/Contents/"
fi
# Copy icon files
if [ -d "$app_source/Contents/Resources" ]; then
mkdir -p "$target/Contents/Resources"
find "$app_source/Contents/Resources" -name "*.icns" -exec cp -f {} "$target/Contents/Resources/" \;
fi
# Symlink the MacOS directory (contains the actual binary)
if [ -d "$app_source/Contents/MacOS" ]; then
ln -sfn "$app_source/Contents/MacOS" "$target/Contents/MacOS"
fi
# Symlink other directories
for dir in "$app_source/Contents"/*; do
dirname=$(basename "$dir")
if [ "$dirname" != "Info.plist" ] && [ "$dirname" != "Resources" ] && [ "$dirname" != "MacOS" ]; then
ln -sfn "$dir" "$target/Contents/$dirname"
fi
done
fi
done
'';
};
}
@motion5
Copy link

motion5 commented Nov 16, 2025

This didn't work for me initially, I'm not sure why, but I found that I was able to fix it by pointing to the correct home-manager path for my system, rather than the system nix profile path in this example. Thank you @Jabb0 for this fix, been trying to resolve this for a while now and yours is the first solution that's allowed it to work with spotlight for me.

Here's the changes I made

-        # Get the target of the symlink
-        NIXAPPS=$(readlink -f "$HOME/.nix-profile/Applications")
+        # Get the target of the symlink from home-manager
+        NIXAPPS="$newGenPath/home-path/Applications"`

this bit is just naming as I believe home manager is creating a symlink that points to the source in nix store and that's what I'm looping through here

-        for app_source in "$NIXAPPS"/*; do
-          if [ -d "$app_source" ] || [ -L "$app_source" ]; then
+        for app_link in "$NIXAPPS"/*; do
+          if [ -d "$app_link" ] || [ -L "$app_link" ]; then
+              # Resolve the symlink to get the actual app in the nix store
+              app_source=$(readlink -f "$app_link")

Here is my full macos-app-fix.nix file

{
  pkgs,
  config,
  lib,
  ...
}:

{
  # Need to copy the apps because otherwise spotlight does not find them.
  home.activation = {
    copyNixApps = lib.hm.dag.entryAfter [ "linkGeneration" ] ''
      # Create directory for the applications
      mkdir -p "$HOME/Applications/Nix Apps"
      # Remove old entries
      rm -rf "$HOME/Applications/Nix Apps"/*
      # Get the target of the symlink from home-manager
      NIXAPPS="$newGenPath/home-path/Applications"
      # For each application
      for app_link in "$NIXAPPS"/*; do
        if [ -d "$app_link" ] || [ -L "$app_link" ]; then
            # Resolve the symlink to get the actual app in the nix store
            app_source=$(readlink -f "$app_link")
            appname=$(basename "$app_source")
            target="$HOME/Applications/Nix Apps/$appname"
            
            # Create the basic structure
            mkdir -p "$target"
            mkdir -p "$target/Contents"
            
            # Copy the Info.plist file
            if [ -f "$app_source/Contents/Info.plist" ]; then
              mkdir -p "$target/Contents"
              cp -f "$app_source/Contents/Info.plist" "$target/Contents/"
            fi
            
            # Copy icon files
            if [ -d "$app_source/Contents/Resources" ]; then
              mkdir -p "$target/Contents/Resources"
              find "$app_source/Contents/Resources" -name "*.icns" -exec cp -f {} "$target/Contents/Resources/" \;
            fi
            
            # Symlink the MacOS directory (contains the actual binary)
            if [ -d "$app_source/Contents/MacOS" ]; then
              ln -sfn "$app_source/Contents/MacOS" "$target/Contents/MacOS"
            fi
            
            # Symlink other directories
            for dir in "$app_source/Contents"/*; do
              dirname=$(basename "$dir")
              if [ "$dirname" != "Info.plist" ] && [ "$dirname" != "Resources" ] && [ "$dirname" != "MacOS" ]; then
                ln -sfn "$dir" "$target/Contents/$dirname"
              fi
            done
          fi
          done
    '';
  };
}

@Jabb0
Copy link
Author

Jabb0 commented Nov 16, 2025

@motion5 amazing. Glad it helped!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment