Packaging guidelines for macOS

Note: This post may be a little out of date as it was originally written in 2015. But I’m posting it here as the fundamentals have not really changed much.

Credits: Thanks to Gary Larizza for his post on where most of this documents content was sourced ( )


When managing Mac OS X devices, you will enviably have to deploy files or applications to many devices. There are many ways to achieve this, however the most effective and best practice method is to use Packages.
While packaging is quite simple, it can very quickly become quite complex. This document serves to provide some guidelines to help you avoid some simple mistakes and prevent confusion when creating packages.


There are many tools out there used to create Packages, Apple offer their own built in command line tools like pkgbuild. This guide will not go into detail about how to use any of these tools, it is up to the system admin’s own personal preference on which tools they wish to use in order to create their packages.
However version control is very important, as is the ability to quickly and accurately create and recreate packages. The ability for packages to be peer reviewed and package versions to easily be diff’d is also important and the admin’s choice of tools should take this into account. It is also highly recommend that a version control system such as git is used in combination with package creation.
Below is a list of tools that are recommended for creating packages:


Packages by Whitebox

A great GUI driven tool to create flat and distribution packages and provides an easy to learn GUI. It is still quite powerful and allows a great deal of control over how your packages are created. A build file is created which saves information on how the package should be created such as the payload, pre/post flight scripts, additional resources etc etc.

Cost: $0 – FREE


The Luggage

A completely text driven package building system perfect for use with version control systems such as Git.  Files can easily be reviewed to see what will be in the package without any extra work.

The big benefit to using The Luggage is that because the packages are created with make files, these make files can easily be diff’d to see changes as well as talking other users through the creation process. No GUI panes to navigate.

Cost: $0 – FREE


Munki PKG

Munki PKG is a simple tool very similar to The Luggage which builds packages in a consistent, repeatable manner from source files and scripts in a project directory.

Files, scripts and metadata are stored in a way that is easy to track and manage using a version control system like git.

Cost: $0 – FREE


The Guidelines

Installation method

Your installer should not require any input from the end user.


  • Assume that your package will be installed interactively via the GUI or to the currently booted volume.  More often than not packages will be deployed to machines via management systems such as Munki or Casper. Because of this you should ensure that your package can be installed to machines that are unattended (at the login window without a console user logged in)


  • Ensure that your package can be installed via the command line and by any management framework with and without a user logged in.


Installation target


  • Assume that your package will be installed to the currently booted volume. Your package might not necessarily be installed to the currently booted volume, so ensure that any scripts in your package use the correct variables passed to it from the installer application. For example, reference the target volume in your scripts by using the variable $3 (in bash) rather than using absolute file references.
  • Use tools such as sw_vers in order to get the Operating System version. These tools will only report the OS of the currently booted volume.


  • Check the SystemVersion.plist on the target volume ($3)
  • Check if the boot volume (/) is the same as the target volume ($3) if any of your scripts require it.

Unnecessary actions.


  • Perform ‘helpful’ things like using osascript to open a Finder window showing your newly installed application. Similarly do not do things like opening a browser window to the installed software’s homepage.
  • The problem with these things is if you are installing the software in an unattended mode where the computer is at the LoginWindow, these types of things will simply cause errors in your installation process.
  • Require unnecessary reboots if you can accomplish the same thing by loading/unloading LaunchDaemons/LaunchAgents – If you go down this path, remember that it is even more important to check if you are installing to the boot volume or not.
  • Automatically add files to the Dock, Desktop or anywhere outside of /Applications or other required directories. If you wish to add Dock items, use another package/script/profile/tool to achieve that.
  • Ask for admin/elevated privileges if they are not needed for installation, i.e. installing into
  • Create separate installers for different architectures/OS versions. If you have separate payloads for separate architectures/OS versions, perform your architecture/OS check on the target volume, not the currently booted operating system see rule 2.


  • Use a distribution meta-package to provide a single package that will correctly determine OS/Architecture of the destination volume and install the appropriate payload.


Licensing should be managed by Systems Administrators. Wherever possible licensing files should be packaged separately to the application being deployed. This allows for a single application package to be deployed to multiple sites with different licensing files applied later depending upon the licence that is appropriate for that site.

Licensing information might be supplied via a global plist/config profile/KMS  or other.

This also prevents unauthorised installation of software should your application package be obtained by a unauthorised third party.


  • Place licensing and registration files in the user’s home directory wherever possible. Use a global location such as /Library
  • Building licensing/registration mechanisms into the installer GUI.


  • Allow a scriptable licensing interface to your software


Pre/Post install scripts

Use pre and post install scripts only when necessary, and follow all other rules with your scripts.

For example, it would be silly to use a package to install some files on disk and then use a post install script to set the permissions of those files. Instead correctly set the permissions of the files in the payload.

This also allows for reviewing of package contents via lsbom


  • Use postinstall scripts to create or modify files – do this in the package payload.
  • If you must use post-install scripts, do not use osascript to move and copy files. Use CLI tools such as cp and mv in bash
  • Use any kind of GUI scripting, see Rule 1.
  • Use sudo in your scripts, your script is already running as root.


  • Exit your script with 0 on success, or non-zero on failure.
  • Trap error codes in your scripts
  • Use globbing in your scripts, because no one likes repetition and computers are built to do the work for us so let them.
  • Ensure your scripts handle paths with spaces in them.

Naming Conventions and Version Numbers

Naming conventions are necessary and helpful. For example VPN.pkg is NOT helpful.

Give your packages meaningful names and version numbers.  Providing vendor and product name, along with important version numbers and vendor identification codes.


  • List your vendor and product name in your package name
  • Give packages meaningful names with version numbers. Remember 1.15 is greater than 1.2 in most situations.

Supporting Operating System Versions

If you are going to supporting running your application or payload on operating systems back to say version 10.8, then it should go without saying that you need to TEST your package on every version from 10.8 to the most current.


  • Change the ownership and permissions of core Operating System folders and files


  • Keep your config data and cache data separate
  • Follow the directory structure mandated by the target platforms software deployment guidelines
  • Provide an uninstaller or uninstall script
  • Use the documented OS X .pkg format and not just a .pkg wrapper for a 3rd party solution that installs the software for you – obvious exception for Adobe software.

Be Descriptive

Even if you are not planning on having your package installed via the GUI you should still make it GUI-friendly.


  • Provide a welcome message, read-me, description of whats happening and whats being installed.
  • Comment your pre/post install scripts thoroughly.


Snapshotting and Re-Packaging

Try to avoid using Snapshot methods to create packages – a common tool used to create snapshot packages is JAMF’s composer.

Snapshotting is generally considered bad juju and the result of a lazy (not in a good way) sysadmin

Packages created from snapshots lack the nuances and intent of the original package. They can often miss critical files or modifications to the file system.

If you are unable to use a vendor package, consider the following:


  • Attempt to unpack and reverse engineer the package – Use tools such as Pacifist ( and pkgutil –expand to determine what the package is attempting to achieve.
  • Try to modify the existing vendor package using things like providing a custom Choices.XML to select certain packages in a meta/distribution package for installation.

Product Signing

Gatekeeper was introduced in 10.8 as a way to alert users to unsigned packages. For this reason, it is best practice to sign your installer packages with a developer ID certificate that lets your users know your packages can be trusted. It also allows packages to be installed in the GUI when Gatekeeper is configured to allow apps downloaded from the App Store and identified developers

Unsigned packages are not an issue when not using the GUI installer however.


  • Use productsign to sign your packages with an Apple Developer ID certificate

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s