Choose a distribution path
Inventory runtime dependencies
List embedded frameworks, helper tools, licenses, external commands, network services, and data migrations before creating a release.
12 minute lesson
Your release is more than the Swift code you wrote. It may embed frameworks, helper tools, fonts, machine learning models, or command-line binaries. It may also assume things exist on the user’s Mac that only exist on yours.
Before packaging anything, take an inventory. Start with the libraries your executable links against:
otool -L Notes.app/Contents/MacOS/Notes
Read the output carefully. System frameworks under /System/Library are fine — every Mac has them. Paths under /opt/homebrew or /usr/local are a problem: they exist on your machine because you installed something, and they will not exist for your users.
Then find every executable inside the bundle, because each one ships (and later gets signed) as part of your app:
find Notes.app/Contents -type f -perm +111 -print
For each redistributed component, record where it came from and what license it carries. “I found it in a build folder” is not an answer you want to give later.
If your app runs external commands, decide the strategy explicitly. Either bundle the tool inside the app, or look for it in known locations and degrade gracefully when it’s missing, or ask the user to locate it. Never assume /opt/homebrew/bin exists on anyone’s Mac.
The classic failure looks like this. The app works perfectly for you for months. A user launches it and it dies instantly with dyld: Library not loaded: /opt/homebrew/lib/libsqlite3.dylib. Your Homebrew installation was a hidden dependency the whole time.
The test that catches this is cheap: run the release artifact on a Mac (or a fresh macOS virtual machine) that has never seen your development setup. If it launches and every feature works, your inventory is complete.
Lesson completed