Skip to main content

winapp-setup

Add Windows SDK and Windows App SDK support to an existing project (winapp init), restore pinned SDKs after cloning (winapp restore), update SDKs, or create a new WinUI app (winapp new). Use for Electron, .NET, C++, Rust, Flutter, or Tauri projects that need Windows setup.

Source facts

Repository
microsoft/winappCli
Last source activity
October 13, 2026 at 17:48
Detected SKILL.md language
English
Stars
1,314
Forks
88

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
winapp-setup
description
Add Windows SDK and Windows App SDK support to an existing project (winapp init), restore pinned SDKs after cloning (winapp restore), update SDKs, or create a new WinUI app (winapp new). Use for Electron, .NET, C++, Rust, Flutter, or Tauri projects that need Windows setup.
**If you can't run `winapp` yourself** (no shell, or the command is denied), give the user the exact `winapp` command(s) for their project instead of only describing the steps. ## When to use Use this skill when: - **Scaffolding a brand-new WinUI 3 app** from an official Windows App SDK template (`winapp new`) - **Adding Windows platform support** to an existing project (Electron, .NET, C++, Rust, Flutter, Tauri, etc.) - **Cloning a repo** that already uses winapp and need to restore SDK packages - **Updating SDK versions** to get the latest Windows SDK or Windows App SDK ## Prerequisites Install the winapp CLI before running any commands: ```powershell # Via winget (recommended for non-Node projects) winget install Microsoft.WinAppCli --source winget # Via npm (recommended for Electron/Node projects — includes Node.js SDK) npm install --save-dev @microsoft/winappcli ``` You need an **existing app project** — `winapp init` does **not** create new projects, it adds Windows platform files to your existing codebase. > **Already have a `Package.appxmanifest`?** .NET projects that already have a packaging manifest (e.g., WinUI 3 apps or projects with an existing MSIX packaging setup) likely **don't need `winapp init`**. Ensure your `.csproj` references the `Microsoft.WindowsAppSDK` NuGet package and has the right properties for packaged builds (e.g., `<WindowsPackageType>MSIX</WindowsPackageType>`). WinUI 3 apps created from Visual Studio templates are typically already fully configured — you can go straight to building and using `winapp run` or `winapp package`. ## Key concepts **`Package.appxmanifest`** is the most important file winapp creates — it declares your app's identity, capabilities, and visual assets. Most winapp commands require it (`package`, `run`, `cert generate --manifest`). **`winapp.yaml`** is only needed for SDK version management via `restore`/`update`. Projects that already reference Windows SDK packages (e.g., via NuGet in a `.csproj`) can use winapp commands without it. **`.winapp/`** is the local folder where SDK packages and generated projections (e.g., CppWinRT headers) are stored. This folder is `.gitignore`d — team members recreate it via `winapp restore`. ## Usage ### Create a new WinUI app To start a brand-new **WinUI** app (rather than adding Windows support to an existing project), use `winapp new`. It verifies the .NET SDK, installs the official WinUI `dotnet new` template pack on demand (grabbing the latest, or offering to update a stale one), and scaffolds the app against your installed SDK's target framework. Most WinUI templates already include packaging/identity, so **no `winapp init` step is needed** afterward — follow the template-specific next step `winapp new` prints when it finishes. App templates go straight to `winapp run` (which builds and launches the app); the `winui-lib` (class library) and `winui-unittest` templates differ (reference the library from an app project, or `winapp run` the packaged test app to run its tests). The template list is read live from the installed pack — run `winapp new --list` to see the current set. The pack ships two styles of app. **XAML** templates (`winui`, `winui-navview`, `winui-tabview`, `winui-mvvm`) define the UI in markup with a C# code-behind. **Reactor** templates (`reactor`, `reactor-mvu`, `reactor-navview`, `reactor-tabview`) are pure C# with no XAML, using an MVU pattern. > **Reactor templates are experimental.** They reference the prerelease `Microsoft.UI.Reactor` packages, whose APIs can change or be removed in a future release — don't pick one unless the user explicitly asks for Reactor. `winapp new` marks them **(Experimental)** in `--list` and in the picker, reports `"Experimental": true` in `--json`, and never selects one as the default. They also require the **.NET 10 SDK or newer**; on an older SDK `winapp new` fails up front naming the version it needs. > A first run, template-pack update, or newly published Windows App SDK version may take longer while missing NuGet packages download and restore. If scaffolding continues beyond 10 seconds, `winapp new` updates its status message rather than silently waiting. ```powershell # Interactive — pick a template, then name/output winapp new # See the available templates without scaffolding winapp new --list # One-shot with a specific template (short names come from `winapp new --list`) winapp new --name MyApp --template winui-navview # Experimental Reactor app (pure C#, no XAML) — requires the .NET 10 SDK winapp new --name MyApp --template reactor-mvu # Diagnose a failed scaffold: --verbose streams dotnet new's post-creation actions # (restore, package add, etc.) live so the underlying dotnet error is visible winapp new --name MyApp --verbose # Always use the newest template pack without prompting winapp new --name MyApp --template-version latest --use-defaults # Non-interactive (agent) with machine-readable output winapp new --use-defaults --name MyApp --json ``` ### Initialize a new winapp project ```powershell # Interactive — prompts for app name, publisher, SDK channel, etc. # Automatically searches for compatible projects (Tauri, Electron, .NET, Rust, C++, Flutter) winapp init # Non-interactive — accepts all defaults (stable SDKs, current folder name as app name) winapp init . --use-defaults # Non-interactive with JS bindings enabled winapp init . --use-defaults --add-js-bindings # Skip SDK installation (just manifest + config) winapp init . --use-defaults --setup-sdks none # Install preview SDKs instead of stable winapp init . --use-defaults --setup-sdks preview ``` After `init`, your project will contain: - `Package.appxmanifest` — package identity and capabilities - `Assets/` — default app icons (Square44x44Logo, Square150x150Logo, etc.) - `winapp.yaml` — SDK version pinning for `restore`/`update` - `.winapp/` — downloaded SDK packages and generated projections - `.gitignore` update — excludes `.winapp/` and `devcert.pfx` When JS bindings are enabled (via `--add-js-bindings` or by answering yes in interactive init), npm/Electron projects also get: - `.winapp/bindings/` — generated JS bindings for Windows App SDK APIs (npm-only, Node / Electron) - `package.json` update — adds the `winapp.jsBindings` namespace and `@microsoft/dynwinrt` dependency (npm-only) ### Initialize a sparse identity package (existing exe) Use `--sparse` when you have an **already-built desktop exe** (WPF, WinForms, Win32, Electron, etc.) and only want to give it **package identity** — without repackaging the whole app into the MSIX. The app's files stay where they are and are resolved from an *external content location* at runtime. ```powershell # Generate an identity-only sparse manifest for an existing exe winapp init --exe ./bin/Release/MyApp.exe --sparse # Non-interactive, with explicit identity values winapp init --exe ./bin/Release/MyApp.exe --sparse --name MyApp --publisher "CN=Contoso" --use-defaults ``` `--sparse` requires `--exe`. It skips all SDK/package installation (sparse identity packages have no SDK dependencies) and, by default, writes to a dedicated `sparse/` folder in the current directory (override with `--output-dir`) so the manifest and its `Assets/` stay out of a build-output folder that a rebuild would wipe: - `appxmanifest.xml` — identity-only sparse manifest (declares `uap10:AllowExternalContent`) - `Assets/` — placeholder visual assets (extracted from the exe's icon when possible), resolved from the **external location** at runtime — **not** bundled into the `.msix` If an `appxmanifest.xml` already exists in the target directory, init fails instead of overwriting it; re-run with `--force` to regenerate. This is step 1 of the sparse packaging workflow. Continue with: 1. `winapp pack ./sparse/appxmanifest.xml --cert ./devcert.pfx` — build the signed identity `.msix` 2. `winapp embed-identity ./bin/Release/MyApp.exe` — connect the exe to the identity package (re-sign the exe afterward) 3. Register in your installer with `Add-AppxPackage -Path <msix> -ExternalLocation <install-dir>` For the full walkthrough, see the [Sparse packaging guide](https://github.com/microsoft/WinAppCli/blob/main/docs/guides/sparse.md). ### Restore after cloning ```powershell # Reinstall SDK packages from existing winapp.yaml (does not change versions) winapp restore # Restore into a specific directory winapp restore ./my-project ``` Use `restore` when you clone a repo that already has `winapp.yaml` but no `.winapp/` folder. For a .NET project there is no `winapp.yaml`, so `restore` runs `dotnet restore` instead. ### Private or custom NuGet feeds `init`, `restore`, and `update` download the SDK packages through NuGet, honoring your standard `nuget.config` hierarchy. Private feeds and mirrors, feed credentials (including credential providers), and a custom `globalPackagesFolder` all work as they do for `dotnet restore`. To use only your feed, `<clear />` the inherited sources first: ```xml <?xml version="1.0" encoding="utf-8"?> <configuration> <packageSources> <clear /> <add key="contoso" value="https://pkgs.dev.azure.com/contoso/_packaging/winsdk-mirror/nuget/v3/index.json" /> </packageSources> </configuration> ``` > **Security note:** For native projects winapp resolves `nuget.config` from the directory it operates on: the `init`/`restore` directory argument, `--config-dir` when given, otherwise the current directory. For **.NET projects** the sources come from the project's own `nuget.config` hierarchy instead, because that is what `dotnet add package` and `dotnet restore` use — so put a private feed's config in the project directory or an ancestor, not in a sibling passed via `--config-dir` (that is reported and ignored). Run these commands only against directories you trust, the same as `dotnet restore`. Use `<packageSourceMapping>` to pin packages to specific feeds when more than one source is configured. ### Update SDK versions ```powershell # Check for and install latest stable SDK versions winapp update # Switch to preview channel winapp update --setup-sdks preview ``` This updates `winapp.yaml` with the latest versions and reinstalls packages. If the newest Windows App SDK release is still being published (some of its packages aren't on the feed yet), `update` uses the previous release instead and prints a note; run `winapp update` again later to pick up the new release. ### Run and debug with identity ```powershell # Register debug identity and launch app from build output winapp run ./bin/Debug # Launch with custom manifest and pass arguments to the app winapp run ./dist --manifest ./out/Package.appxmanifest --args "--my-flag value" # Pass arguments after -- to avoid escaping (equivalent to --args) winapp run ./bin/Debug -- --my-flag value # Register identity without launching (useful for attaching a debugger manually) winapp run ./bin/Debug --no-launch # Launch and capture OutputDebugString messages and crash diagnostics # Note: prevents other debuggers (VS, VS Code) from attaching — use --no-launch if you need those instead winapp run ./bin/Debug --debug-output ``` Use `winapp run` during iterative development — it creates a loose layout package, registers a debug identity, and launches the app in one step. For identity-only registration without loose layout, use `winapp create-debug-identity` instead. #### Project mode: `winapp run` on a `.csproj` (.NET / WinUI) For .NET SDK projects you can point `winapp run` **at the project instead of the build output** — it builds the `.csproj` and launches it in one step, so there's no separate `dotnet build` and no need to know the output path: ```powershell # Build and run the project in the current directory (input defaults to ".") winapp run # Run a specific project, configuration, and architecture winapp run ./src/MyApp/MyApp.csproj -c Release --arch arm64 # Force an unpackaged run of a packaged project winapp run . -p WindowsPackageType=None # Show winapp's build decision traces (dotnet build stays at minimal verbosity) winapp run . --verbose # Test a project configured with <PublishAot>true</PublishAot> winapp run . --aot winapp run . --aot -c Release ``` Project mode supports both **packaged** and **unpackaged** WinUI apps, detected from the project's effective `WindowsPackageType` (`MSIX` ⇒ loose-layout register + AUMID launch; `None` ⇒ launch the built `.exe`), and installs the matching-architecture Windows App Runtime before launching. RID-only remains the default; when the effective configuration requires a self-contained profile, winapp selects the architecture-matching profile without forcing that platform onto referenced `AnyCPU` libraries. Requires .NET SDK 8.0.100+. - **Build inputs:** `-c/--configuration`, `--arch`, `-r/--runtime`, `-f/--framework`, `--no-build`, `--no-restore`, `--aot`, `-p/--property` (repeat for multiple properties; use `%3B` or `%2C` for a literal semicolon or comma in a value). `--aot` supports x64/ARM64 projects, requires .NET SDK 8.0.300+ and effective `PublishAot=true`, and cannot use `--no-build` or `--manifest`; configure the project manifest before publishing. - **Packaged-only options:** `--manifest`, `--no-launch`, `--with-alias`, `--clean`, `--unregister-on-exit`, `--output-appx-directory`, `--executable`, `--unique-identity` — rejected for unpackaged apps. - **Output:** winapp restores dependencies, then builds; successful-build warnings stay visible. Interactive terminals show a one-line restore result and dotnet's own build output; other output uses sanitized plain lines that stream live. A failed restore or build prints the exact `dotnet` command; `--verbose` prints every command. `--json` sends restore/build invocations and child output to **stderr** so stdout stays valid JSON. `--quiet` suppresses invocations and sends dotnet's quiet restore/build output to **stderr** so stdout stays clean. With `--aot`, `--verbose` adds the publish command and resolved paths; publish diagnostics go to **stderr** under `--json`/`--quiet`. For parallel packaged checkouts, see `winapp-identity` and the canonical [`--unique-identity` workflow](https://github.com/microsoft/WinAppCli/blob/main/docs/usage.md#unique-identity-for-parallel-checkouts). Do not add this flag to an unpackaged run or automatically remove another checkout's registration to make normal mode succeed. #### Project mode: `winapp run` on a C++ `.vcxproj` A Visual Studio C++ project (for example the **WinUI Blank App (Packaged)** C++/WinRT template) runs the same way. winapp builds it with Visual Studio's MSBuild (restoring `packages.config` first), then launches it packaged or unpackaged: ```powershell winapp run .\MyApp.vcxproj winapp run . -c Release --arch arm64 --detach --json ``` Requires Visual Studio or Build Tools with the **Desktop development with C++** workload (WinUI 3 apps also need **C++ WinUI app development tools**); the .NET SDK is not needed. If the C++ build tools, platform toolset, or Windows SDK are missing, the error says what to install. `--framework` and `--aot` are .NET-only. #### Single-file mode: `winapp run` on a `.cs` file-based app A .NET 10 file-based app is a single `.cs` file configured by `#:` directives, with no project file. Point `winapp run` at it and the app builds and launches **with package identity** — no hand-written manifest: ```powershell # Build and run a file-based app with identity winapp run counter.cs # Register identity without launching, or run a Release build detached winapp run counter.cs --no-launch winapp run counter.cs -c Release --detach --json # Remove the package it registered winapp unregister counter.cs ``` Describe the package with `#:property` directives in the file. All are optional: | Property | Sets | Default | |---|---|---| | `WinAppPackageName` | `Identity/@Name` | file name (sanitized) + a short hash of its path | | `WinAppDisplayName` | Start/Settings name | file name | | `WinAppPublisher` | `Identity/@Publisher` | `CN=<current user>`; a bare name is wrapped as `CN=` | | `WinAppVersion` | `Identity/@Version` | `$(Version)`, normalized to four 0–65535 parts (`1.2.3-preview.4` ⇒ `1.2.3.0`) | | `WinAppDescription` | Install/Settings description | the display name | | `WinAppCapabilities` | Capabilities to declare, separated by `;` or `,` | none | | `WinAppRunUseExecutionAlias` | Launch via execution alias instead of AUMID, so console output stays in the terminal | `true` for `OutputType=Exe`, else `false` |
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub