> For the complete documentation index, see [llms.txt](https://docs.flatredball.com/gum/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flatredball.com/gum/cli/cli/pack.md).

# pack

```
gumcli pack <project.gumx> [-o <path>] [--include <categories>]
```

Loads a `.gumx` project, walks its dependencies, and writes a single-file `.gumpkg` bundle (tar + brotli) containing the requested file categories. Use this when you want to ship a single file with your game instead of a folder of loose `.gumx`/`.gusx`/`.gucx`/`.gutx` files plus textures and fonts.

{% hint style="info" %}
The Gum WYSIWYG editor still saves loose files. `.gumpkg` is purely a packaging format produced by `gumcli pack` — there is no "Save as bundle" option in the editor.
{% endhint %}

## Options

* `<project>` — Path to the `.gumx` project file (positional argument)
* `-o, --output <path>` — Output path. Defaults to `<ProjectName>.gumpkg` next to the `.gumx`.
* `--include <categories>` — Comma-separated list of file categories to include. Defaults to `core,fontcache,external`. Valid values:
  * `core` — the `.gumx` plus all `.gusx`, `.gucx`, `.gutx`, and `.behx` files referenced by the project
  * `fontcache` — generated bitmap font files under `FontCache/` (`.fnt` + `.png` pages)
  * `external` — files referenced by the project but outside Core/FontCache, such as sprite source `.png` textures, `CustomFontFile` paths, and a `Font` value that points at a project-relative `.ttf` file rather than a system font family name (e.g. `Fonts/MyFont.ttf` vs. `Arial`)

{% hint style="info" %}
**Shipping September 2026:** Packing a `.ttf` referenced through the `Font` property (not just `CustomFontFile`) will ship in the September release, or now if building Gum from source. Before this, only `CustomFontFile` paths were bundled as external font files.
{% endhint %}

## Examples

Pack with default categories (everything):

```
gumcli pack GumProject/GumProject.gumx
```

Pack to a specific output path:

```
gumcli pack GumProject/GumProject.gumx -o build/GumProject.gumpkg
```

Omit the font cache (e.g. when your build pipeline regenerates bitmap fonts via `gumcli fonts`):

```
gumcli pack GumProject/GumProject.gumx --include core,external
```

## Output

The command prints per-category file counts together with uncompressed and compressed byte sizes plus the overall compression ratio, for example:

```
Packed 83 files into C:\Games\MyGame\GumProject.gumpkg
  Core:          42
  FontCache:     18
  External:      23
Uncompressed:    2003532 bytes
Compressed:      541210 bytes
Ratio:           27.0%
```

## Loading a `.gumpkg` at runtime

Pass the bundle to `Initialize` in place of the `.gumx`:

```csharp
// Initialize
GumService.Default.Initialize(graphics, gumProjectFile: "GumProject.gumpkg");
```

The extension you pass decides how Gum loads the project. A path ending in `.gumx` (or `.gumj`) reads loose files, and a path ending in `.gumpkg` serves every element, texture, and font read from inside the bundle. Gum does not look for a sibling file of the other kind, so a `.gumpkg` sitting next to your loose project is ignored unless you pass its path to `Initialize`.

A bundle path resolves from the same starting folder as a loose project path. On MonoGame, KNI, and FNA that folder is your game's `Content` folder, so `"GumProject/GumProject.gumx"` loads `Content/GumProject/GumProject.gumx` and the sample above loads `Content/GumProject.gumpkg`. On raylib the path starts at the folder holding the executable, so a project loaded as `"resources/GumProject/GumProject.gumx"` becomes `"resources/GumProject.gumpkg"`.

{% hint style="warning" %}
A bundle keeps the file name of the project it holds. Gum reads a `.gumpkg` by looking inside it for a project file of the same name, so `GumProject.gumpkg` must hold `GumProject.gumx`, and loading a renamed bundle throws. The comparison is exact, including capitalization, on every platform. `-o` names the file to write, so point it at a different folder rather than a different name.
{% endhint %}

{% hint style="info" %}
Bundle loading is available on MonoGame, KNI, FNA, and raylib. SkiaGum and Silk.NET load loose project files only, so pass them a `.gumx` path.
{% endhint %}

That includes a `.ttf` the project references through `Font` or `CustomFontFile`. Runtime font generation (KernSmith on MonoGame, KNI, FNA, and raylib) reads the font out of the bundle, so a project that rasterizes its fonts at runtime runs from a `.gumpkg` alone with no loose files and no `FontCache/` folder.

{% hint style="info" %}
**Shipping September 2026:** Reading a bundled `.ttf` at runtime ships in the September release, or now if building Gum from source. Before this, the font was packed into the `.gumpkg` but the runtime looked for it on disk and fell back to the default font.
{% endhint %}

Because the choice is just the string you pass, a game can keep loose files while developing, where [hot reload](/gum/code/debugging/hot-reload.md) works, and load the bundle in a published build. How it decides between the two paths is up to you.

## Packing From Your Build

Running `gumcli pack` by hand before every release is easy to forget, and a stale `.gumpkg` looks exactly like a fresh one. An MSBuild target packs the project as part of the build instead, so the bundle is always as new as the files it came from.

### Make GumCli available to the build

Install **GumCli** as a *local* tool so the version is recorded in source control and build machines do not need a global install. Run this once in your repository root:

```
dotnet new tool-manifest
dotnet tool install GumCli
```

This creates `.config/dotnet-tools.json`, which you check in. On a fresh clone or a build server, `dotnet tool restore` installs the recorded version, and you invoke the tool as `dotnet gumcli`.

If you would rather install **GumCli** globally (`dotnet tool install -g GumCli`), invoke it as plain `gumcli` in the examples below, and make sure every build machine has it installed.

### Add the target

Add the following to your game's `.csproj`, adjusting the paths to match your project:

```xml
<ItemGroup>
    <GumSourceFile Include="Content\GumProject\**\*.*" />
</ItemGroup>

<Target Name="PackGumProject"
        AfterTargets="Build"
        Condition="'$(Configuration)' == 'Release'"
        Inputs="@(GumSourceFile)"
        Outputs="$(OutDir)Content\GumProject.gumpkg">
    <Exec Command="dotnet tool restore" />
    <MakeDir Directories="$(OutDir)Content" />
    <Exec Command="dotnet gumcli pack &quot;Content\GumProject\GumProject.gumx&quot; -o &quot;$(OutDir)Content\GumProject.gumpkg&quot;"
          WorkingDirectory="$(MSBuildProjectDirectory)" />
</Target>
```

The paths above follow the MonoGame, KNI, and FNA layout, where the Gum project lives in `Content\GumProject` and the game loads it as `"GumProject.gumpkg"`. On raylib, swap `Content` for `resources` in both the item and the output path, and load the bundle as `"resources/GumProject.gumpkg"`.

What each piece does:

* `AfterTargets="Build"` runs the pack once the normal build finishes, so the bundle lands in the build output alongside the rest of your content. `dotnet publish` does not carry it any further, so see [Packing for publish](#packing-for-publish) if you publish.
* `Condition` limits packing to `Release` builds, since Debug builds keep loading loose files, which is what hot reload needs. Your game has to ask for the bundle only in the configuration that produces one, or it looks for a `.gumpkg` that was never written.
* `Inputs` and `Outputs` make the target incremental. MSBuild skips it when the bundle is newer than every file in the Gum project, so an unchanged project does not pay for a repack on every build.
* `MakeDir` creates the content folder, because `pack` writes the bundle but does not create the folder holding it.
* `WorkingDirectory` lets you write the project path relative to the `.csproj` instead of spelling out an absolute path.

`gumcli pack` returns a non-zero exit code when a referenced file is missing or the project fails to load, and `Exec` turns that into a build failure. A project with a broken reference fails the build instead of shipping a bundle with holes in it.

### Keep loose files out of a release build

Every configuration copies the loose `.gumx` and its element files to the output folder, through the `CopyToOutputDirectory` entry you added when [setting up the project](/gum/code/getting-started/setup/loading-a-gum-project-.gumx.md). Add a condition to that entry so a `Release` build ships only the bundle:

```xml
<ItemGroup Condition="'$(Configuration)' != 'Release'">
    <None Update="Content\GumProject\**\*.*">
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
</ItemGroup>
```

Each configuration then ships only the files it loads.

### Packing for publish

A bundle written into the build output is not copied to the publish folder, so a game you ship with `dotnet publish` wants its own target:

```xml
<Target Name="PackGumProjectForPublish" AfterTargets="Publish">
    <Exec Command="dotnet tool restore" />
    <MakeDir Directories="$(PublishDir)Content" />
    <Exec Command="dotnet gumcli pack &quot;Content\GumProject\GumProject.gumx&quot; -o &quot;$(PublishDir)Content\GumProject.gumpkg&quot;"
          WorkingDirectory="$(MSBuildProjectDirectory)" />
</Target>
```

### Regenerating fonts first

If your build also generates bitmap fonts, run [`gumcli fonts`](/gum/cli/cli/fonts.md) before packing so the `FontCache` files exist when `pack` looks for them:

```xml
<Exec Command="dotnet gumcli fonts &quot;Content\GumProject\GumProject.gumx&quot;"
      WorkingDirectory="$(MSBuildProjectDirectory)" />
```

{% hint style="info" %}
`gumcli fonts` is Windows only, since it drives `bmfont.exe`. On a Linux or macOS build agent, either commit the generated `FontCache` files to source control, or pack with `--include core,external` and let the runtime rasterize fonts from a `.ttf`.
{% endhint %}

## Exit Codes

| Code | Meaning                                                                                                    |
| ---- | ---------------------------------------------------------------------------------------------------------- |
| 0    | Bundle written successfully                                                                                |
| 1    | One or more dependency files were missing on disk                                                          |
| 2    | Project failed to load, project file not found or unreadable, or an invalid `--include` value was supplied |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.flatredball.com/gum/cli/cli/pack.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
