Skill v1.0.0
Trusted Publisher100/100version: "1.0.0" name: winapp-package description: Package a Windows app as an MSIX installer for distribution or testing. Use when creating a Windows installer, packaging an Electron/Flutter/.NET/Rust/C++/Tauri app for Windows, building an MSIX, distributing a desktop app, packaging a console app or CLI tool, or adding MSIX packaging to a build script or CI/CD pipeline.
When to use
Use this skill when:
- Creating an MSIX installer from a built app for distribution or testing
- Packaging any Windows app — GUI apps, console apps, CLI tools, services, or background processes
- Signing a package with a development or production certificate
- Bundling the Windows App SDK runtime for self-contained deployment
Prerequisites
What you need depends on the input:
- Project mode (
winapp package MyApp.csproj): an explicit.csprojfor a packaged app (EnableMsixTooling=truewith aPackage.appxmanifest). winapp publishes it and packages the output. - Folder mode (
winapp package ./bin/Release): built app output in a folder (e.g.,bin/Release/,dist/,build/) plus a `Package.appxmanifest` in the current directory, passed via--manifest, or in the folder. - Certificate (optional, both modes) —
devcert.pfxfromwinapp cert generatefor signing.
Usage
Package directly from a .csproj (project mode)
# Publish the project and create an MSIX in one step (no need to build or locate the output first)winapp package ./MyApp.csproj# Override configuration/architecture, or sign in the same step (project mode defaults to Release)winapp package ./MyApp.csproj -c Debug --arch arm64 --cert ./devcert.pfx# Package an already-built output without rebuildingwinapp package ./MyApp.csproj --no-build# Produce an architecture .msixbundle from one project (publishes each arch, then bundles)winapp package ./MyApp.csproj --arch x64 --arch arm64 --cert ./devcert.pfx
Project mode is triggered only by an explicit .csproj. It publishes the project — so trimmed or self-contained apps package what actually ships — with the build options (-c/--configuration, --arch, -f/--framework, --no-build, --no-restore, repeatable -p), defaults to the Release configuration, resolves the published output, and packages it. If the project publishes as an unpackaged app (WindowsPackageType=None) there is no manifest to package and the command errors. Folder, bundle, and sparse-manifest inputs are unchanged.
Basic packaging (unsigned)
# Package from build output — manifest auto-detected from current dir or input folderwinapp package ./bin/Release# Specify manifest location explicitlywinapp package ./dist --manifest ./Package.appxmanifest
Package and sign in one step
# Sign with existing certificatewinapp package ./bin/Release --cert ./devcert.pfx# Custom certificate passwordwinapp package ./bin/Release --cert ./devcert.pfx --cert-password MyP@ssw0rd
Generate certificate + package in one step
# Auto-generate cert, sign, and packagewinapp package ./bin/Release --generate-cert# Also install the cert to trust it on this machine (requires admin)winapp package ./bin/Release --generate-cert --install-cert
Unsigned output (Store submission or external signing)
# Force an unsigned package. For a .csproj that configures its own signing, this overrides it.# Cannot be combined with --cert or --generate-cert.winapp package ./MyApp.csproj --no-sign
Self-contained deployment
# Bundle Windows App SDK runtime so users don't need it installed (must have winappsdk reference in the winapp.yaml or *.csproj)winapp package ./bin/Release --cert ./devcert.pfx --self-contained
Custom output path and name
# Specify output filewinapp package ./dist --output ./releases/myapp-v1.0.msix --cert ./devcert.pfx# Custom package namewinapp package ./dist --name "MyApp_1.0.0_x64" --cert ./devcert.pfx
What the command does
- Locates `Package.appxmanifest` — looks in input folder, then current directory (or uses
--manifest) - Copies manifest + assets into a staging layout alongside your app files
- Discovers manifest-referenced files — any non-image file referenced in the manifest (e.g., AppExtension payloads like
manifest.json, config files) is automatically copied from the manifest directory or input folder if missing from staging - Generates `resources.pri` — Package Resource Index for UWP-style resource lookup (skip with
--skip-pri) - Runs `makeappx pack` — creates the
.msixpackage file - Signs the package (if
--certprovided) — callssigntoolwith your certificate
Output: a .msix file that can be installed on Windows via double-click or Add-AppxPackage.
Installing the MSIX for testing
# Trust the dev certificate first (one-time, requires admin)winapp cert install ./devcert.pfx# Install the MSIXAdd-AppxPackage ./myapp.msix# Uninstall if neededGet-AppxPackage *myapp* | Remove-AppxPackage
Recommended workflow
- Build your app (
dotnet build,cmake --build,npm run make, etc.) - Package —
winapp package <build-output> --cert ./devcert.pfx - Trust cert (first time) —
winapp cert install ./devcert.pfx(admin) - Install — double-click the
.msixorAdd-AppxPackage ./myapp.msix - Test the installed app from the Start menu
Advanced: External content catalog
For sparse packages with AllowExternalContent, you may need a code integrity catalog:
# Generate CodeIntegrityExternal.cat for external executableswinapp create-external-catalog "./bin/Release"# Include subdirectories and specify output pathwinapp create-external-catalog "./bin/Release" --recursive --output ./catalog/CodeIntegrityExternal.cat
Bundling multiple architectures
Create an MSIX bundle from multiple per-architecture build outputs:
# Create unsigned bundle for Store submission (x64 + arm64)winapp package ./publish/x64 ./publish/arm64# Create signed bundle for sideloadingwinapp package ./publish/x64 ./publish/arm64 --cert ./devcert.pfx# Self-contained bundle with Windows App SDK runtime per archwinapp package ./publish/x64 ./publish/arm64 --self-contained --generate-cert
How it works: When multiple input folders are passed, winapp package:
- Detects the architecture of each folder's primary executable from its PE header
- Resolves a manifest for each slice (see below)
- Validates that all slices share the same Identity, Capabilities, and Dependencies
- Packs each folder into an intermediate unsigned
.msix - Bundles them into a single
.msixbundleusingmakeappx bundle - Signs only the bundle (not individual slices) — the signature covers all packages inside
Manifest resolution: Each slice needs a manifest. Resolution order:
--manifest <path>uses one manifest for all slices (architecture auto-stamped per folder)- Per-folder
Package.appxmanifestif present in the input folder - Fallback to
Package.appxmanifestin the current working directory
The ProcessorArchitecture is always force-set to the detected architecture per-slice. All other Identity fields must be consistent across slices.
Output: <Name>_<Version>_<arch1>_<arch2>.msixbundle (architectures sorted alphabetically).
Store submission: An unsigned bundle is valid for Store upload — Partner Center signs it with your reserved identity certificate. For sideloading, pass --cert or --generate-cert.
This hashes executables in the specified directories so Windows trusts them when running with sparse package identity.
CI/CD
GitHub Actions
Use the microsoft/setup-winapp action to install winapp on GitHub-hosted runners:
- uses: microsoft/setup-winapp@v1- name: Packagerun: winapp package ./dist --cert ${{ secrets.CERT_PATH }} --cert-password ${{ secrets.CERT_PASSWORD }} --quiet
Tips for CI/CD pipelines:
- Use
--quiet(or-q) to suppress progress output - Use
--if-exists skipwithwinapp cert generateto avoid regenerating existing certificates - Store your PFX certificate as a repository secret and decode it in CI
- Use
--use-defaults(or--no-prompt) withwinapp initto avoid interactive prompts
Tips
- The
packagecommand aliases topack— both work identically Package.appxmanifestPublisher must match the certificate publisher — usewinapp cert generate --manifestto ensure they match- Use
--skip-priif your app doesn't use Windows resource loading (e.g., most Electron/Rust/C++ apps without UWP resources) - For framework-specific packaging paths (Electron, .NET, Rust, etc.), see the
winapp-frameworksskill - The
--executableflag overrides the entry point in the manifest — useful when your exe name differs from what's inPackage.appxmanifest - For production distribution, use a certificate from a trusted CA and add
--timestampwhen signing withwinapp sign
Sparse identity packages
To grant identity to an app distributed by an existing installer (not as MSIX), build an identity-only sparse package: pass a sparse appxmanifest.xml (one declaring <uap10:AllowExternalContent>true</uap10:AllowExternalContent> under <Properties>) to winapp pack instead of a folder.
# 1. Generate the sparse manifest for your exe (skips SDK install)winapp init --exe ./bin/Release/MyApp.exe --sparse --use-defaults# 2. Build & sign the identity-only .msix (just the manifest)winapp pack ./sparse/appxmanifest.xml --cert ./devcert.pfx# 3. Embed identity into the exe, then register in your installerwinapp embed-identity ./bin/Release/MyApp.exe
The .msix contains only the manifest — binaries and assets are resolved from the external content location at runtime via Add-AppxPackage -ExternalLocation. If you pack a folder whose manifest declares AllowExternalContent, winapp pack warns about any assets/binaries found. See the Sparse Packaging Guide.
Related skills
- Need a manifest first? See
winapp-manifestto generatePackage.appxmanifest - Need a certificate? See
winapp-signingfor certificate generation and management - Having issues? See
winapp-troubleshootfor a command selection flowchart and error solutions
Troubleshooting
| Error | Cause | Solution | ||
|---|---|---|---|---|
| "Package.appxmanifest not found" | No manifest in input folder or current dir | Run winapp init or winapp manifest generate first | ||
| "Publisher mismatch" | Cert publisher ≠ manifest publisher | Regenerate cert with winapp cert generate --manifest, or edit manifest | ||
| "Package installation failed" | Cert not trusted or stale package | Run winapp cert install ./devcert.pfx (admin), then `Get-AppxPackage <name> \ | Remove-AppxPackage` | |
| "makeappx not found" | Build tools not downloaded | Run winapp update or winapp tool makeappx --help to trigger download |
CLI reference
Run winapp <command> --help for current command options, or winapp --cli-schema for the complete machine-readable command schema.