Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This article describes how to get started writing XBOX games, tools, and services in C# with the Microsoft Game Development Kit (GDK). It points you to XBOX GDK.NET, the .NET projection of the GDK flat C API, which exposes the Gaming Runtime, XBOX services, and PlayFab as ordinary modern C#, and explains what you need in order to run and ship a .NET title on XBOX on PC and on XBOX Series X|S.
.NET is one of several ways you can build with the GDK. For an overview of the engine and framework options and how the GDK fits into each one, see Microsoft Game Development Kit and game engines.
XBOX GDK.NET
XBOX GDK.NET is a source-only reference projection on GitHub. It is a working example of how to bind the Microsoft GDK, XBOX services, and PlayFab into a .NET application, so you can write your title in C# rather than in P/Invoke. The projection is modular: the Gaming Runtime is always present, and XBOX services and each PlayFab group are opt-in at packaging time, so a title that doesn't use a family doesn't carry it.
Important
XBOX GDK.NET requires at least the April 2026 Microsoft GDK Update 4. For the current minimum edition, see the supported versions matrix in the repository, which is the canonical source. Building the projection needs no GDK install at all; running against the Gaming Runtime needs the GDK, a dev-unlocked machine, and a signed-in account.
What's included
XBOX GDK.NET projects the GDK surface a .NET title actually needs, generated and verified against the real GDK headers rather than transcribed by hand:
- Gaming Runtime - users and sign-in, game invites and protocol activation, storage, packages and DLC, game saves, game UI, networking, capture and broadcast, the Store, game streaming, accessibility, speech, and system metadata
- XBOX services - profile, achievements, social, presence, privacy, leaderboards, real-time activity, user and title-managed statistics, title storage, string verification, events, multiplayer activity, plus the social and achievements manager layers
- PlayFab - Core and the full generated Services surface, Game Saves, Multiplayer (Lobby and Matchmaking), and Party including PartyXboxLive
- NativeAOT - AOT-safe on
net8.0andnet10.0, enforced by analyzers, warnings-as-errors, and a real ILC compilation in CI, because consoles don't permit JIT
Coverage is measured rather than asserted: effectively the whole Gaming Runtime and PlayFab export surface is bound, with only a small number of entry points deliberately out of scope. The repository ships eng/api-coverage.ps1, which diffs the bound entry points against each native module's export table, so you can get the current tally for the edition you have installed. For the per-family breakdown, and for what is excluded and why, see Projection status in the repository.
The projection ships no native code of its own. Every P/Invoke binds to a redistributable module that the GDK already installs.
What the projection replaces
The point of XBOX GDK.NET is that a caller never sees a raw flat C convention. Everything the GDK expresses through HRESULTs, handles, and async blocks is expressed instead through the .NET idiom a C# developer already knows:
| Microsoft GDK (flat C) | XBOX GDK.NET |
|---|---|
HRESULT return codes |
Exceptions (GameRuntimeException and typed subclasses); the numeric code is preserved on HResultCode |
XAsyncBlock plus a completion callback plus a second "get result" call |
Task / Task<T>, awaited normally |
| Two-call size-then-buffer reads | Ordinary properties and return values |
Opaque handles with X*CloseHandle |
IDisposable |
XUserRegisterForChangeEvent plus a registration token |
C# event; unsubscribing unregisters |
E_ABORT from a cancelled operation |
OperationCanceledException via CancellationToken |
X*Flags integer constants |
[Flags] enums |
Initializing the runtime and signing in a user is ordinary C#. GameRuntime is both the entry point and the lifetime owner, and the family managers hang off the instance:
using GDK.Net;
using GDK.Net.Users;
using GameRuntime runtime = GameRuntime.Initialize();
using User user = await runtime.Users
.AddAsync(UserAddOptions.AddDefaultUserSilently)
.ConfigureAwait(false);
Console.WriteLine($"id 0x{user.Id:X16}, state {user.State}");
In C, those reads are XUserGetId and XUserGetState, each returning an HRESULT with the value in an out parameter. For the idioms in full, see Getting started in the repository.
Opt-in modules
XBOX services and PlayFab are separate native modules, so you choose them at packaging time. eng/packaging/GdkRedist.targets copies the modules you asked for next to the executable on every build.
| Opt-in property | Native modules | Managed surface |
|---|---|---|
| (always) | xgameruntime.thunks.dll |
GDK.Net - the Gaming Runtime: GameRuntime, UserManager, GamePackage, GameSaveProvider, StoreContext, NetworkingManager, and the rest |
<GdkNetIncludeXboxLive> |
Microsoft.Xbox.Services.C.Thunks.dll, libHttpClient.dll |
GameRuntime.XboxLive - profile, achievements, social, presence, privacy, leaderboards, stats, title storage, and the manager layers |
<GdkNetIncludePlayFab> |
PlayFabCore.dll, PlayFabServices.dll, PlayFabGameSave.dll, libHttpClient.dll |
GDK.Net.PlayFab - PlayFabRuntime, the generated service classes, PlayFabGameSaveFiles |
<GdkNetIncludePlayFabMultiplayer> |
PlayFabMultiplayer.dll |
GDK.Net.PlayFab.Multiplayer - lobbies and matchmaking |
<GdkNetIncludePlayFabParty> |
Party.dll, PartyXboxLive.dll |
GDK.Net.PlayFab.Party - voice, text chat, and network transport |
The last two PlayFab groups import PlayFabCore.dll, so asking for either turns <GdkNetIncludePlayFab> on as well.
Supported runtimes and engines
| Runtime | Tier |
|---|---|
net8.0 (LTS) |
Primary |
net10.0 (LTS) |
Primary |
netstandard2.0 |
Compatibility (MonoGame / Mono / broad reach) |
All three runtimes target win-x64. The supported architectures, GDK editions, .NET SDK versions, and build toolchain are listed in the supported versions matrix in the repository, which is kept current as new editions are validated.
All three targets export an identical public surface; what differs is how that surface is implemented. The net8.0 and net10.0 targets use [LibraryImport] and [UnmanagedCallersOnly] function pointers, which is what makes them AOT-safe; netstandard2.0 uses [DllImport] and delegates, and exists solely for MonoGame and Mono reach. For the detail, see Architecture.
MonoGame, Stride, and bespoke .NET hosts and tooling on Windows are supported engine and framework targets. Only Microsoft-supported .NET LTS releases are targeted, and the window moves as LTS releases ship and reach end of life.
What this is and what it isn't
This is a source-only projection, not a product. It's MIT-licensed at the wrapper layer; the Microsoft GDK and the PlayFab extension libraries it binds to are installed and licensed separately, consistent with our other XBOX samples.
There is no set update cadence for support or maintenance. We'll watch the repo, monitor issues, and iterate where it makes sense, but this isn't a commercial release. That said, we're excited to hear your feedback, and see any community PRs, as we evolve this together.
Supports only Windows and consoles through the GDK. There is no Linux or macOS support.
Requirements to run
The Gaming Runtime refuses to initialize in a process with no package identity, so running a .NET title against it needs more than the .NET SDK:
| To do this | You need |
|---|---|
| Build the library and run the unit tests | A current .NET SDK. No GDK install required. |
| Run anything against the Gaming Runtime | An installed Microsoft GDK, a dev-unlocked Windows machine, and an account signed in to the XBOX app |
| Package a title | The GDK, for makepkg.exe |
| Publish with NativeAOT | The MSVC toolchain, because ILC shells out to link.exe |
Packaging is not required in order to run. On PC, title identity can come from a MicrosoftGame.config beside the executable rather than from a registered package, so a plain dotnet run or a self-contained publish works on a dev-unlocked machine. Packaging remains what a title ships as.
Get started
Building needs nothing but the .NET SDK:
dotnet restore
dotnet build -c Release
dotnet test -c Release --no-build
Use these resources to clone the repository, build the projection, and start integrating it with your .NET project:
- XBOX GDK.NET: microsoft/XBOX-GDK-dotnet - The .NET projection of the Microsoft GDK, XBOX services, and PlayFab.
- Microsoft GDK: microsoft/GDK - Microsoft Public GDK.
- PlayFab SDK: PlayFab Unified SDK - PlayFab Unified SDK.
- Documentation: XBOX GDK.NET documentation index - Getting started, building, architecture, projection status, and the generated API reference.
- Samples:
samples/GDK.Net.UserSampleandsamples/GDK.Net.PlayFabSample- Readable end-to-end demos of sign-in and of the PlayFab surface. - Issues: XBOX GDK.NET issues - Report bugs, request features, or contribute back.
After you have integrated the Microsoft GDK with your .NET project, follow the rest of the PC end-to-end guide to register your title, set up your product in Partner Center, and publish your game to the Microsoft Store.
Support for XBOX Series X|S and XBOX One
XBOX consoles don't permit JIT compilation, so a .NET title that ships to console must be NativeAOT-compiled. XBOX GDK.NET is AOT-safe on net8.0 and net10.0, and the repository enforces that with AOT, trim, and single-file analyzers under warnings-as-errors, a real ILC compilation in CI, and a live packaged run on hardware.
AOT is opt-in, not imposed. An ordinary dotnet build, dotnet test, or dotnet publish is unchanged and JIT-compiled, which is what you'll normally use while developing for XBOX on PC. To AOT-publish a title of your own:
dotnet publish -c Release -f net10.0 -r win-x64 --self-contained -p:PublishAot=true
Two environment notes:
Use
net10.0(ornet9.0), notnet8.0. The NativeAOT runtime pack was first published for 9.0, so anet8.0AOT publish can't be restored with a 10.x SDK. XBOX GDK.NET still targetsnet8.0for framework-dependent consumers; only the AOT publish needs the newer target framework.vswhere.exemust be onPATH. ILC resolveslink.exeby shelling out tovswhere, so when it's missing you get an opaqueMSB3073rather than a clear error. Avcvars64shell is not sufficient.
For the background on why NativeAOT matters for games, what it costs you, and how to structure a codebase for it, see NativeAOT for gaming. For the full contract and the verification steps behind it, see NativeAOT in the repository.
If you are building for XBOX Series X|S or XBOX One, contact your XBOX representative. If you are not yet registered, see Register for the ID@XBOX program to get started.