macOS Packaging
Package your Wails application for macOS distribution
Private macOS APIs
Wails v3 uses public macOS APIs by default. To opt into features that require undocumented Apple APIs, build your app with the single Go build tag private_mac_apis:
wails3 build -tags private_mac_apis
EXTRA_TAGS=private_mac_apis wails3 dev
wails3 package GOOS=darwin EXTRA_TAGS=private_mac_apis
For a direct Go build, use go build -tags private_mac_apis . (or -tags production,private_mac_apis for production). Existing applications that depend on private behavior must add this tag to retain it. The tag applies only to macOS desktop builds.
See Private macOS APIs for the complete inventory of affected features and option values, exact public-build fallbacks, Liquid Glass style mappings, and inspector build combinations. Private-only operations are no-ops without the tag; the public Go API is unchanged.
Application Bundle
Package your app as a standard macOS .app bundle:
wails3 package GOOS=darwin
This creates bin/<AppName>.app containing:
- The compiled binary in
Contents/MacOS/ - App icon in
Contents/Resources/(fromicons.icnsor, when present, from an asset catalogAssets.car) Info.plistwith app metadata
Projects in synced folders
Some macOS file providers add Finder metadata to .app directories. This causes codesign to reject the bundle, or invalidates its signature after signing. Removing the metadata alone is insufficient when the provider adds it again.
The generated macOS build tasks check for this behavior. When detected, Wails moves the project’s generated output directory to ~/Library/Application Support/Wails/build-output/<project>-<hash> and replaces the original output directory with a symlink. Existing output files are preserved, and bin/<AppName>.app remains the path used by packaging, signing, and dev mode. The CLI prints the local storage location when it performs the move.
Set WAILS_MACOS_OUTPUT_ROOT to choose another local, unsynced storage location. The relocation root must be on the same filesystem as the project. An explicit BIN_DIR outside the project is used as configured. Existing projects need the updated build/darwin/Taskfile.yml to use this handling.
For distribution, copy bin/<AppName>.app or create a DMG. Copying the bin symlink alone does not include the build artifacts. The direct wails3 tool sign command reports an error if its input folder reattaches metadata; move that bundle to an unsynced folder before signing it.
Bundle Resources
Contents/Resources/ is the standard place for read-only files that ship with a macOS app. Use it for larger templates, seed data, media, language packs, or other payloads that should be opened on demand rather than compiled into the Go executable with embed.
Wails already places the application icon in this directory. To add your own files, place them in a source directory such as build/resources/, then add a copy step to the create:app:bundle task in build/darwin/Taskfile.yml:
tasks:
create:app:bundle:
cmds:
# Existing bundle creation commands...
- |
if [ -d build/resources ]; then
cp -R build/resources/. "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Resources/"
fiIf you use the Taskfile’s darwin:run task, add the equivalent command to its run task, targeting {{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Resources/.
Reading Resources from Go
Import the macOS platform package:
import (
"io/fs"
"github.com/wailsapp/wails/v3/pkg/mac"
)For small files, use LoadResource:
func loadSplash() ([]byte, error) {
return mac.LoadResource("images/splash.png")
}For larger files, use ResourceFS. It returns an io/fs.FS rooted at Contents/Resources, so callers can open and stream a resource without first loading it all into a Go byte slice:
func openCatalogue() (fs.File, error) {
resources, err := mac.ResourceFS()
if err != nil {
return nil, err
}
return resources.Open("catalogue/defaults.json")
}Resource names are slash-separated paths relative to Contents/Resources. ResourceFS and LoadResource return mac.ErrNotInAppBundle unless the executable runs from .app/Contents/MacOS.
Treat bundle resources as immutable. Changing files inside a signed application invalidates its code signature; store downloaded, generated, or user-editable data in the user’s Application Support directory instead.
Universal Binary
Build for both Apple Silicon and Intel Macs:
wails3 task darwin:package:universal
This creates a single .app that runs natively on both architectures. Universal binaries can be built on any platform — on Linux and Windows, wails3 tool lipo is used automatically.
Customizing the Bundle
Edit build/darwin/Info.plist to customize:
- Bundle identifier (
CFBundleIdentifier) - App name and version
- Minimum macOS version
- File associations
- URL schemes
The app icon is generated from assets in the build/ directory. Use the generate:icons task:
wails3 task common:generate:icons
This uses build/appicon.png to produce darwin/icons.icns and windows/icon.ico. On macOS you can also provide build/appicon.icon (Icon Composer format): the task passes -iconcomposerinput appicon.icon -macassetdir darwin, which produces Assets.car and darwin/icons.icns from the .icon file (skipped on non-macOS platforms). When Assets.car is present, run the update:build-assets task so that Info.plist and CFBundleIconName are updated accordingly:
wails3 task common:update:build-assets
To run the icon command manually from the build/ directory:
cd build
wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico -iconcomposerinput appicon.icon -macassetdir darwin
Code Signing
Sign your app for distribution:
# Using the wrapper (auto-detects platform)
wails3 sign GOOS=darwin
# Or using the task directly
wails3 task darwin:sign
Configure signing in build/darwin/Taskfile.yml:
vars:
SIGN_IDENTITY: "Developer ID Application: Your Company (TEAMID)"
ENTITLEMENTS: "build/darwin/entitlements.plist"Notarization
For apps distributed outside the Mac App Store, Apple requires notarization:
wails3 task darwin:sign:notarize
First, store your credentials. Either run the interactive wizard (wails3 setup signing) or call notarytool directly:
xcrun notarytool store-credentials "my-notarize-profile" \
--apple-id "you@email.com" \
--team-id "TEAMID" \
--password "app-specific-password"
Configure in build/darwin/Taskfile.yml:
vars:
SIGN_IDENTITY: "Developer ID Application: Your Company (TEAMID)"
KEYCHAIN_PROFILE: "my-notarize-profile"See Signing Applications for details.
DMG Installer
The shipped Wails 3 template provides wails3 task darwin:package:dmg. It creates the .app first and then builds a styled DMG with the DMG library. By default, the DMG uses a Wails-branded gradient backdrop with the red dragon mark and WAILS wordmark.
wails3 task darwin:package:dmg
The lower-level darwin:create:dmg task creates a DMG from an existing .app bundle and can be configured directly from the Taskfile:
vars:
# These are the template defaults; override them when needed.
DMG_BACKGROUND: build/darwin/dmg-background.png
DMG_VOLUME_ICON: build/darwin/icons.icns
DMG_FILE_ICON: build/darwin/dmg-file-icon.icns
DMG_WINDOW_WIDTH: 540
DMG_WINDOW_HEIGHT: 380
DMG_FILES: "Install.command=build/darwin/Install.command,README.txt=README.md"Default Layout
The generated DMG contains:
- The application bundle on the left
- An
Applicationslink on the right - A Finder window sized to 540×380 pixels
- A 96-point icon size with labels beneath each icon
- The Wails-branded background from
build/darwin/dmg-background.png
The application and Applications icons are positioned relative to the configured window dimensions, so changing DMG_WINDOW_WIDTH or DMG_WINDOW_HEIGHT keeps the default two-icon layout proportionally spaced. For the best result, use a background image with the same pixel dimensions as the Finder window.
Replacing the DMG Assets
The generated files under build/darwin/ are normal project assets and may be replaced:
DMG_BACKGROUNDcontrols the image displayed behind the Finder window contents.DMG_VOLUME_ICONcontrols the icon shown for the mounted volume.DMG_FILE_ICONcontrols the icon shown for the resulting.dmgfile in Finder.
The volume icon and DMG file icon are separate resources. Replacing the application icon does not automatically replace either of them.
Adding Extra Files
Use DMG_FILES to include installer scripts, release notes, licences, or other resources alongside the application. The value is a comma-separated list of name=path pairs:
vars:
DMG_FILES: "Install.command=build/darwin/Install.command,README.txt=README.md"The name before = is the filename shown inside the DMG. The path after = is the source file in the project. Leading and trailing whitespace is ignored.
Each displayed name must be unique. Extra files cannot replace entries already created by the packager, including the application bundle or the Applications entry. A conflicting name causes packaging to fail with an error rather than producing a broken DMG.
Troubleshooting
“App is damaged and can’t be opened”
The app isn’t signed. Either sign it with a Developer ID certificate, or users can bypass Gatekeeper:
xattr -cr /path/to/YourApp.app
Notarization fails
Common issues:
- Invalid credentials: Re-run
xcrun notarytool store-credentials(orwails3 setup signing) - Hardened runtime required: Ensure entitlements include
com.apple.security.cs.allow-unsigned-executable-memoryif needed - Missing timestamp: The signing process should include a timestamp automatically
Cross-compiled app won’t run
Cross-compiled macOS binaries aren’t signed. Transfer to a Mac and sign before testing:
codesign --force --deep --sign - YourApp.app