Many Windows APIs (push notifications, background tasks, share target, startup tasks, Windows AI APIs) require your app to have package identity. During development, you don't want to build a full MSIX installer every time you test — winapp provides two commands to give your app identity on the fly.
Using Visual Studio with a packaging project? If you are already using Visual Studio for your packaged project, you likely don't need winapp for debugging. Visual Studio already handles package registration, identity, AUMID activation, debugger attachment, and activation-code debugging — all from F5. It also offers Debug → Other Debug Targets → Debug Installed App Package for advanced scenarios. The workflows below are most useful for VS Code users, terminal-based workflows, and frameworks that VS doesn't natively package (Rust, Flutter, Tauri, Electron, plain C++).
winapp run |
create-debug-identity |
|
|---|---|---|
| What it registers | Full loose layout package (entire folder) | Sparse package (single exe) |
| How the app launches | Launched by winapp (AUMID activation or execution alias) | You launch the exe yourself (command line, IDE, etc.) |
| Simulates MSIX install | Yes — closest to production behavior | No — sparse identity only |
| Files stay in place | Copied to an AppX layout directory | Yes — exe stays at its original path |
| Identity scope | Entire folder contents (exe, DLLs, assets) | Single executable |
| Debugger-friendly | Attach to PID after launch, or use --no-launch then launch via alias |
Launch directly from your IDE's debugger — the exe has identity regardless |
| Console app support | --with-alias keeps stdin/stdout in terminal |
Run exe directly in terminal |
| Best for | Most frameworks (.NET, C++, Rust, Flutter, Tauri) | Electron, or when you need full IDE debugger control (F5) |
Use winapp run for most development workflows. It simulates a real MSIX install — your app gets the same identity, capabilities, and file associations it would have in production.
# Build your app, then:
winapp run .\build\output- Your exe is separate from your build output — e.g., Electron apps where
electron.exelives innode_modules/ - You need to debug startup code and can't attach a debugger fast enough after AUMID launch
- With some debuggers where you can't launch with AUMID and need identity on the launched process —
create-debug-identityregisters the exe so it has identity no matter how it's started - You're testing sparse package behavior specifically (AllowExternalContent, TrustedLaunch)
# Register identity for an exe, then launch it however you want:
winapp create-debug-identity .\bin\Debug\myapp.exe
.\bin\Debug\myapp.exe # or F5 in your IDEThe simplest workflow — build, run with identity, done.
winapp run .\build\DebugWinapp registers the folder as a loose layout package and launches the app. Identity-requiring APIs work immediately. This covers the majority of development and testing scenarios.
For console apps that need stdin/stdout in the current terminal, add --with-alias:
winapp run .\build\Debug --with-aliasLaunch with winapp run, note the PID, then attach your IDE's debugger.
winapp run .\build\Debug
# Output: Process ID: 12345Then in your IDE:
- VS Code: Run and Debug → select "Attach" configuration (see IDE setup below)
- WinDbg:
windbg -p 12345
Limitation: You'll miss any code that runs before you attach. For startup debugging, use Scenario D (
create-debug-identity).
Use --no-launch to register the package, then launch the app through its AUMID (reported by run) or execution alias from your IDE.
Step 1: Register the package without launching:
winapp run .\build\Debug --no-launchStep 2: Configure your IDE to launch via the AUMID or the execution alias (not the exe directly).
- Launching with AUMID: Use the command
start shell:AppsFolder\<AUMID>.winapp runoutputs the AUMID when the app is registered. - Launching with the alias: The alias must be defined in the appxmanifest.xml (or Package.appxmanifest).
Important: Simply launching the exe in the build folder will not give it identity. The app must be started via AUMID activation or its execution alias. This is how loose layout packages work - identity is tied to the activation path, not the exe file.
This is the best approach for debugging startup code with full IDE control - your IDE's debugger controls the process from the very first instruction, and the exe has identity no matter how it's launched.
winapp create-debug-identity .\build\Debug\myapp.exeNow launch the exe any way you like — from the terminal, from VS Code's F5, from a script. The exe has identity because Windows registered a sparse package pointing directly at it.
How it differs from
winapp run: Withcreate-debug-identity, identity is tied to the exe itself (viaAdd-AppxPackage -ExternalLocation). Withwinapp run, identity is tied to the loose layout package — the app must be launched through AUMID or an alias. This makescreate-debug-identitythe better choice when you need your IDE to launch and debug the exe directly.
This is also the best approach for Electron apps where the exe path differs from your source directory.
Capture OutputDebugString messages and first-chance exceptions inline. Framework noise (WinUI, COM, DirectX internal traces) is filtered from the console so only your app's debug messages appear. Everything is still written to the log file for full investigation.
If the app crashes, a minidump is captured and analyzed automatically:
winapp run .\build\Debug --debug-outputOn crash, the output includes the exception type, message, and stack trace with source file and line numbers (resolved from PDBs in your build output folder). Managed (.NET) crashes are analyzed instantly with no external tools. Native (C++/WinRT) crashes show module names and offsets; add --symbols to download PDB symbols for full function names:
winapp run .\build\Debug --debug-output --symbolsImportant: This attaches winapp as the debugger. Windows only allows one debugger per process, so you cannot also attach Visual Studio, VS Code, or WinDbg.
Attach to running process — add to .vscode/launch.json:
{
"name": "Attach to Process",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}For C++/Rust, use "type": "cppvsdbg" (MSVC) or "type": "lldb" (LLDB):
{
"name": "Attach (C++)",
"type": "cppvsdbg",
"request": "attach",
"processId": "${command:pickProcess}"
}