How to Use the macOS pkgbuild Command to Compile Enterprise Installer Packages

The Deployment Problem

When an enterprise IT department needs to deploy a custom application (like a proprietary internal logging tool, a specialized font library, or a Python script) to 5,000 corporate Macs, they use a Mobile Device Management (MDM) solution like Jamf Pro or Microsoft Intune.

However, MDM platforms cannot magically deploy raw scripts or loose files. They require a highly specific, standardized wrapper: the macOS Installer Package (.pkg file). If you simply zip a folder of files and upload it to Intune, the deployment will fail.

Many administrators rely on paid, third-party graphical applications (like Composer or AutoPkg) to generate these installers. But graphical tools are slow, impossible to integrate into automated CI/CD pipelines (like GitHub Actions), and often leave behind messy, bloated metadata.

To compile pristine, enterprise-grade installer packages directly from the command line, macOS engineers use the native pkgbuild command. pkgbuild allows you to define a payload directory, inject pre-install and post-install bash scripts, cryptographically sign the package with an Apple Developer ID, and compile the final .pkg file in a single execution, making it the bedrock of automated Mac deployment.

Step 1: Preparing the Payload (The Root Directory)

The fundamental concept of a .pkg file is mapping. You are telling the macOS Installer: “Take these files and put them exactly here on the user’s hard drive.”

To do this, you must create a “Root Directory” on your desktop that perfectly mimics the structure of the target hard drive.

Suppose you are deploying a custom corporate application named CorpLogger.app, and you want it installed into the standard /Applications/Utilities/ folder on the user’s Mac.

First, build the directory structure in a staging folder on your Desktop:

mkdir -p ~/Desktop/PkgStaging/Root/Applications/Utilities/

Next, copy your actual application into that deeply nested folder:

cp -R /path/to/CorpLogger.app ~/Desktop/PkgStaging/Root/Applications/Utilities/

When pkgbuild compiles the package, it will look inside the Root folder, see the Applications folder, and understand exactly where the payload belongs.

Step 2: Preparing the Scripts (Preinstall and Postinstall)

Often, dropping a file onto the hard drive is not enough. You might need to kill a running process before the installation starts, or you might need to use launchctl to load a background daemon the exact second the installation finishes.

You achieve this by creating a Scripts directory.

mkdir -p ~/Desktop/PkgStaging/Scripts/

Inside this folder, create a bash script named exactly postinstall (no .sh extension). The macOS Installer engine specifically looks for files with this exact name.

nano ~/Desktop/PkgStaging/Scripts/postinstall

Add your bash automation logic:

#!/bin/bash
# Forcefully launch the application immediately after installation
open /Applications/Utilities/CorpLogger.app
exit 0

Make sure the script is executable, or the installer will fail:

chmod +x ~/Desktop/PkgStaging/Scripts/postinstall

Step 3: Compiling the Package (pkgbuild)

You now have a Root folder (the payload) and a Scripts folder (the automation). You are ready to compile the binary package.

Use the pkgbuild command, passing the root path, the scripts path, a unique reverse-DNS identifier (so the OS can track the installation receipt), and the output filename.

pkgbuild --root ~/Desktop/PkgStaging/Root \
         --scripts ~/Desktop/PkgStaging/Scripts \
         --identifier com.corp.logger \
         --version 1.0 \
         --install-location / \
         ~/Desktop/CorpLogger_v1.pkg

Decoding the Flags:

  • --root: Points to the payload mapping directory.
  • --scripts: Points to the automation scripts.
  • --identifier: A unique name. If you ever deploy version 2.0 with this exact same identifier, macOS will intelligently upgrade the existing files rather than duplicating them.
  • --install-location /: Tells the installer to map the Root folder starting at the absolute base of the Mac hard drive (Macintosh HD).

The terminal will output Wrote package to /Users/admin/Desktop/CorpLogger_v1.pkg. The package is now fully functional, but it is not ready for the enterprise.

Step 4: Cryptographically Signing the Package

If you upload an unsigned .pkg file to Jamf or Intune, or if you ask a user to download it from an intranet site, macOS Gatekeeper will violently block the installation, throwing an “Unidentified Developer” warning.

To deploy the package silently via MDM, it must be cryptographically signed using an official Apple Developer ID Installer Certificate.

First, find the exact name of your certificate in your Mac’s Keychain using the security command:

security find-identity -p macappstore -v

You will see an output like: "Developer ID Installer: Acme Corporation (X1Y2Z3A4B5)".

Now, simply re-run the pkgbuild command, but append the --sign flag with the exact string of your certificate:

pkgbuild --root ~/Desktop/PkgStaging/Root \
         --scripts ~/Desktop/PkgStaging/Scripts \
         --identifier com.corp.logger \
         --version 1.0 \
         --install-location / \
         --sign "Developer ID Installer: Acme Corporation (X1Y2Z3A4B5)" \
         ~/Desktop/CorpLogger_Signed_v1.pkg

macOS will invoke the codesign framework, prompt you for your Keychain password (if not pre-authorized), and cryptographically seal the package. When an MDM pushes this package, Gatekeeper will mathematically verify the signature against Apple’s servers and allow the installation to proceed silently with full root privileges.

Conclusion

Relying on graphical packaging utilities slows down deployment pipelines and obscures the underlying mechanics of macOS software distribution. By mastering the pkgbuild command, Mac administrators can programmatically map payloads, inject sophisticated bash automation scripts, and cryptographically sign enterprise installers, fully automating the creation of zero-touch deployment packages for their MDM infrastructure.

RELATED POSTS

  • How to Use the macOS pmset Command to Diagnose Power Management and Sleep Issues
  • How to Use the macOS systemextensionsctl Command to Manage Modern Kernel Security
  • How to Configure macOS Firmware Passwords for Physical Endpoint Security
  • How to Implement MDM Configuration Profiles for macOS Kernel Extensions
  • How to Use the macOS asr Command for Block-Level Disk Cloning and Imaging
  • Get the best tech tips delivered straight to your inbox.

    Join thousands of readers mastering Apple, Google, Microsoft, and Linux.